mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-18 02:33:15 +00:00
feat: add security governance contract types (#3270)
This commit is contained in:
Generated
+7
@@ -9971,6 +9971,13 @@ dependencies = [
|
|||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustfs-security-governance"
|
||||||
|
version = "1.0.0-beta.7"
|
||||||
|
dependencies = [
|
||||||
|
"thiserror 2.0.18",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustfs-signer"
|
name = "rustfs-signer"
|
||||||
version = "1.0.0-beta.7"
|
version = "1.0.0-beta.7"
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ members = [
|
|||||||
"crates/s3select-api", # S3 Select API interface
|
"crates/s3select-api", # S3 Select API interface
|
||||||
"crates/s3select-query", # S3 Select query engine
|
"crates/s3select-query", # S3 Select query engine
|
||||||
"crates/scanner", # Scanner for data integrity checks and health monitoring
|
"crates/scanner", # Scanner for data integrity checks and health monitoring
|
||||||
|
"crates/security-governance", # Security governance contracts
|
||||||
"crates/signer", # client signer
|
"crates/signer", # client signer
|
||||||
"crates/targets", # Target-specific configurations and utilities
|
"crates/targets", # Target-specific configurations and utilities
|
||||||
"crates/trusted-proxies", # Trusted proxies management
|
"crates/trusted-proxies", # Trusted proxies management
|
||||||
@@ -108,6 +109,7 @@ rustfs-s3-ops = { path = "crates/s3-ops", version = "1.0.0-beta.7" }
|
|||||||
rustfs-s3select-api = { path = "crates/s3select-api", version = "1.0.0-beta.7" }
|
rustfs-s3select-api = { path = "crates/s3select-api", version = "1.0.0-beta.7" }
|
||||||
rustfs-s3select-query = { path = "crates/s3select-query", version = "1.0.0-beta.7" }
|
rustfs-s3select-query = { path = "crates/s3select-query", version = "1.0.0-beta.7" }
|
||||||
rustfs-scanner = { path = "crates/scanner", version = "1.0.0-beta.7" }
|
rustfs-scanner = { path = "crates/scanner", version = "1.0.0-beta.7" }
|
||||||
|
rustfs-security-governance = { path = "crates/security-governance", version = "1.0.0-beta.7" }
|
||||||
rustfs-signer = { path = "crates/signer", version = "1.0.0-beta.7" }
|
rustfs-signer = { path = "crates/signer", version = "1.0.0-beta.7" }
|
||||||
rustfs-trusted-proxies = { path = "crates/trusted-proxies", version = "1.0.0-beta.7" }
|
rustfs-trusted-proxies = { path = "crates/trusted-proxies", version = "1.0.0-beta.7" }
|
||||||
rustfs-targets = { path = "crates/targets", version = "1.0.0-beta.7" }
|
rustfs-targets = { path = "crates/targets", version = "1.0.0-beta.7" }
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
# Copyright 2024 RustFS Team
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
|
||||||
|
[package]
|
||||||
|
name = "rustfs-security-governance"
|
||||||
|
version.workspace = true
|
||||||
|
edition.workspace = true
|
||||||
|
license.workspace = true
|
||||||
|
repository.workspace = true
|
||||||
|
rust-version.workspace = true
|
||||||
|
homepage.workspace = true
|
||||||
|
description = "Security governance contracts for RustFS."
|
||||||
|
keywords = ["security", "governance", "admin", "rustfs"]
|
||||||
|
categories = ["web-programming", "development-tools"]
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
doctest = false
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror = { workspace = true }
|
||||||
@@ -0,0 +1,257 @@
|
|||||||
|
// Copyright 2024 RustFS Team
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use std::collections::BTreeSet;
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub enum HttpMethod {
|
||||||
|
Delete,
|
||||||
|
Get,
|
||||||
|
Head,
|
||||||
|
Post,
|
||||||
|
Put,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HttpMethod {
|
||||||
|
pub const fn as_str(self) -> &'static str {
|
||||||
|
match self {
|
||||||
|
Self::Delete => "DELETE",
|
||||||
|
Self::Get => "GET",
|
||||||
|
Self::Head => "HEAD",
|
||||||
|
Self::Post => "POST",
|
||||||
|
Self::Put => "PUT",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AdminActionRef(&'static str);
|
||||||
|
|
||||||
|
impl AdminActionRef {
|
||||||
|
pub const fn new(action: &'static str) -> Self {
|
||||||
|
Self(action)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn as_str(self) -> &'static str {
|
||||||
|
self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum PublicRouteKind {
|
||||||
|
ConsoleAsset,
|
||||||
|
Health,
|
||||||
|
OidcBootstrap,
|
||||||
|
StsFormPost,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum RouteRiskLevel {
|
||||||
|
Normal,
|
||||||
|
Sensitive,
|
||||||
|
High,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub enum AdminRouteAccess {
|
||||||
|
AdminAction(AdminActionRef),
|
||||||
|
Public(PublicRouteKind),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AdminRouteAccess {
|
||||||
|
pub const fn admin_action(self) -> Option<AdminActionRef> {
|
||||||
|
match self {
|
||||||
|
Self::AdminAction(action) => Some(action),
|
||||||
|
Self::Public(_) => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn public_kind(self) -> Option<PublicRouteKind> {
|
||||||
|
match self {
|
||||||
|
Self::AdminAction(_) => None,
|
||||||
|
Self::Public(kind) => Some(kind),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||||
|
pub struct AdminRouteSpec {
|
||||||
|
method: HttpMethod,
|
||||||
|
path: &'static str,
|
||||||
|
access: AdminRouteAccess,
|
||||||
|
risk_level: RouteRiskLevel,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AdminRouteSpec {
|
||||||
|
pub const fn admin(method: HttpMethod, path: &'static str, action: AdminActionRef, risk_level: RouteRiskLevel) -> Self {
|
||||||
|
Self {
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
access: AdminRouteAccess::AdminAction(action),
|
||||||
|
risk_level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn public(method: HttpMethod, path: &'static str, kind: PublicRouteKind, risk_level: RouteRiskLevel) -> Self {
|
||||||
|
Self {
|
||||||
|
method,
|
||||||
|
path,
|
||||||
|
access: AdminRouteAccess::Public(kind),
|
||||||
|
risk_level,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn method(self) -> HttpMethod {
|
||||||
|
self.method
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn path(self) -> &'static str {
|
||||||
|
self.path
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn access(self) -> AdminRouteAccess {
|
||||||
|
self.access
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn risk_level(self) -> RouteRiskLevel {
|
||||||
|
self.risk_level
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error, PartialEq, Eq)]
|
||||||
|
pub enum AdminRouteMatrixError {
|
||||||
|
#[error("admin route spec at index {index} has an empty path")]
|
||||||
|
EmptyPath { index: usize },
|
||||||
|
|
||||||
|
#[error("admin route spec at index {index} for {method} {path} has an empty admin action")]
|
||||||
|
EmptyAdminAction {
|
||||||
|
index: usize,
|
||||||
|
method: &'static str,
|
||||||
|
path: &'static str,
|
||||||
|
},
|
||||||
|
|
||||||
|
#[error("duplicate admin route spec for {method} {path}")]
|
||||||
|
DuplicateRoute { method: &'static str, path: &'static str },
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn validate_admin_route_specs(specs: &[AdminRouteSpec]) -> Result<(), AdminRouteMatrixError> {
|
||||||
|
let mut routes = BTreeSet::new();
|
||||||
|
|
||||||
|
for (index, spec) in specs.iter().copied().enumerate() {
|
||||||
|
if spec.path.trim().is_empty() {
|
||||||
|
return Err(AdminRouteMatrixError::EmptyPath { index });
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(action) = spec.access.admin_action()
|
||||||
|
&& action.as_str().trim().is_empty()
|
||||||
|
{
|
||||||
|
return Err(AdminRouteMatrixError::EmptyAdminAction {
|
||||||
|
index,
|
||||||
|
method: spec.method.as_str(),
|
||||||
|
path: spec.path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if !routes.insert((spec.method, spec.path)) {
|
||||||
|
return Err(AdminRouteMatrixError::DuplicateRoute {
|
||||||
|
method: spec.method.as_str(),
|
||||||
|
path: spec.path,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const SERVER_INFO: AdminActionRef = AdminActionRef::new("ServerInfoAdminAction");
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn validates_admin_and_public_route_specs() {
|
||||||
|
let specs = [
|
||||||
|
AdminRouteSpec::admin(HttpMethod::Get, "/rustfs/admin/v3/info", SERVER_INFO, RouteRiskLevel::Sensitive),
|
||||||
|
AdminRouteSpec::public(HttpMethod::Post, "/", PublicRouteKind::StsFormPost, RouteRiskLevel::Sensitive),
|
||||||
|
];
|
||||||
|
|
||||||
|
assert!(validate_admin_route_specs(&specs).is_ok());
|
||||||
|
assert_eq!(specs[0].access().admin_action().expect("admin spec must expose action"), SERVER_INFO);
|
||||||
|
assert_eq!(
|
||||||
|
specs[1].access().public_kind().expect("public spec must expose public kind"),
|
||||||
|
PublicRouteKind::StsFormPost
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_duplicate_method_and_path() {
|
||||||
|
let specs = [
|
||||||
|
AdminRouteSpec::admin(HttpMethod::Get, "/rustfs/admin/v3/info", SERVER_INFO, RouteRiskLevel::Sensitive),
|
||||||
|
AdminRouteSpec::admin(
|
||||||
|
HttpMethod::Get,
|
||||||
|
"/rustfs/admin/v3/info",
|
||||||
|
AdminActionRef::new("StorageInfoAdminAction"),
|
||||||
|
RouteRiskLevel::Sensitive,
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
let err = validate_admin_route_specs(&specs).expect_err("duplicate route spec should fail validation");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
err,
|
||||||
|
AdminRouteMatrixError::DuplicateRoute {
|
||||||
|
method: "GET",
|
||||||
|
path: "/rustfs/admin/v3/info"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_empty_paths() {
|
||||||
|
let specs = [AdminRouteSpec::admin(
|
||||||
|
HttpMethod::Get,
|
||||||
|
" ",
|
||||||
|
SERVER_INFO,
|
||||||
|
RouteRiskLevel::Sensitive,
|
||||||
|
)];
|
||||||
|
|
||||||
|
let err = validate_admin_route_specs(&specs).expect_err("empty path should fail validation");
|
||||||
|
|
||||||
|
assert_eq!(err, AdminRouteMatrixError::EmptyPath { index: 0 });
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn rejects_empty_admin_actions() {
|
||||||
|
let specs = [AdminRouteSpec::admin(
|
||||||
|
HttpMethod::Get,
|
||||||
|
"/rustfs/admin/v3/info",
|
||||||
|
AdminActionRef::new(" "),
|
||||||
|
RouteRiskLevel::Sensitive,
|
||||||
|
)];
|
||||||
|
|
||||||
|
let err = validate_admin_route_specs(&specs).expect_err("empty admin action should fail validation");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
err,
|
||||||
|
AdminRouteMatrixError::EmptyAdminAction {
|
||||||
|
index: 0,
|
||||||
|
method: "GET",
|
||||||
|
path: "/rustfs/admin/v3/info"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2024 RustFS Team
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
pub mod admin_matrix;
|
||||||
|
|
||||||
|
pub use admin_matrix::{
|
||||||
|
AdminActionRef, AdminRouteAccess, AdminRouteMatrixError, AdminRouteSpec, HttpMethod, PublicRouteKind, RouteRiskLevel,
|
||||||
|
validate_admin_route_specs,
|
||||||
|
};
|
||||||
@@ -5,15 +5,14 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
|
|||||||
## Current Context
|
## Current Context
|
||||||
|
|
||||||
- Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
|
- Issue: [`rustfs/backlog#660`](https://github.com/rustfs/backlog/issues/660)
|
||||||
- Branch: `overtrue/arch-admin-route-matrix-guard`
|
- Branch: `overtrue/arch-security-governance-types`
|
||||||
- Baseline: `upstream/main` at `dee550a831cbfc24aa5cecd60f6f3a4cfe1a2e30`
|
- Baseline: `upstream/main` at `c03c0ebc363209a4820e6d6f2267e0342c6a7782`
|
||||||
- PR type for this branch: `test-only`
|
- PR type for this branch: `contract`
|
||||||
- Runtime behavior changes: none
|
- Runtime behavior changes: none
|
||||||
- Rust code changes: add test-only admin route matrix coverage, test-only
|
- Rust code changes: add the pure `rustfs-security-governance` contract crate
|
||||||
registered route tracking, and a private shared admin route registration helper
|
with admin route matrix metadata types, typed validation errors, and unit tests.
|
||||||
so tests exercise the production registration sequence.
|
|
||||||
- CI/script changes: none
|
- CI/script changes: none
|
||||||
- Docs changes: record the route matrix guard handoff.
|
- Docs changes: record the Phase 1 security-governance contract handoff.
|
||||||
|
|
||||||
## Phase 0 Tasks
|
## Phase 0 Tasks
|
||||||
|
|
||||||
@@ -63,43 +62,61 @@ Status values: `[ ]` not started, `[~]` in progress, `[x]` complete, `[!]` block
|
|||||||
when a register entry lacks a source marker, or when a source marker omits a
|
when a register entry lacks a source marker, or when a source marker omits a
|
||||||
removal condition.
|
removal condition.
|
||||||
|
|
||||||
|
## Phase 1 Security Governance Tasks
|
||||||
|
|
||||||
|
- [x] `S-001` Add `crates/security-governance`.
|
||||||
|
- Acceptance: the crate is a workspace member and has no dependency on
|
||||||
|
`rustfs`, `ecstore`, admin handlers, Axum, or runtime state.
|
||||||
|
- Verification: `cargo check -p rustfs-security-governance`.
|
||||||
|
- [x] `S-002` Add admin route matrix core types.
|
||||||
|
- Acceptance: `AdminRouteSpec`, `AdminRouteAccess`, `AdminActionRef`,
|
||||||
|
`PublicRouteKind`, `RouteRiskLevel`, and validation errors model route
|
||||||
|
governance metadata without registering routes or enforcing auth.
|
||||||
|
- Verification: `cargo test -p rustfs-security-governance`.
|
||||||
|
- [ ] `S-003` Add redaction contract types.
|
||||||
|
- [ ] `S-004` Add serde policy marker types.
|
||||||
|
- [ ] `S-005` Add supply-chain policy contract types.
|
||||||
|
- [ ] `S-006` Add `rustfs/src/admin/route_policy.rs` backed by these contract
|
||||||
|
types, without changing route registration or auth behavior.
|
||||||
|
|
||||||
## Next PRs
|
## Next PRs
|
||||||
|
|
||||||
1. `contract`: define the config-model contract surface while preserving the
|
1. `contract`: add redaction, serde policy, or supply-chain governance contract
|
||||||
existing `Config`, `KV`, and `KVS` behavior.
|
modules inside rustfs-security-governance.
|
||||||
2. `ci-gate`: add focused checks for public re-export and storage trait coverage
|
2. `contract`: add an admin route policy table that consumes the new
|
||||||
before pure moves.
|
admin_matrix types while preserving route registration and auth behavior.
|
||||||
|
|
||||||
## Pre-Push Review Log
|
## Pre-Push Review Log
|
||||||
|
|
||||||
| Expert | Status | Notes |
|
| Expert | Status | Notes |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Quality/architecture | pass | Confirmed the matrix helpers keep the snapshot explicit, `S3Router` instrumentation is fully `cfg(test)`, the production registration order is shared through one private helper, and the non-test insertion path keeps existing route construction/insert behavior |
|
| Quality/architecture | pass | Confirmed this is a pure `contract` PR: the new crate has a narrow admin_matrix module, typed errors via thiserror, no dependency on implementation crates, and no route registration or auth integration |
|
||||||
| Migration preservation | pass | Confirmed this remains `test-only` in effect: no route handler/auth/alias semantics changed, no storage hot-path/global-state/crate-split changes, and MinIO admin alias coverage is expanded across all admin-prefix matrix entries |
|
| Migration preservation | pass | Confirmed no runtime code paths changed: no admin handler/router edits, no startup/global-state/storage hot-path movement, no compatibility wrappers, and no behavior drift |
|
||||||
| Testing/verification | pass | Confirmed focused route tests pin `ENV_HEALTH_ENDPOINT_ENABLE=true`, use the production registration helper, and pass with formatting, non-test cargo check, migration guard scripts, diff check, full `make pre-commit`, and temporary unaccounted-route negative coverage |
|
| Testing/verification | pass | Confirmed focused unit tests cover valid admin/public specs, duplicate method/path rejection, empty path rejection, and empty action rejection; focused checks, migration guard scripts, dependency tree review, diff check, and full `make pre-commit` passed |
|
||||||
|
|
||||||
## Verification Notes
|
## Verification Notes
|
||||||
|
|
||||||
Passed:
|
Passed:
|
||||||
|
- `cargo check -p rustfs-security-governance`
|
||||||
|
- `cargo test -p rustfs-security-governance`
|
||||||
- `cargo fmt --all --check`
|
- `cargo fmt --all --check`
|
||||||
- `cargo check -p rustfs --lib`
|
- `cargo tree -p rustfs-security-governance --edges normal`
|
||||||
- `cargo test -p rustfs admin::route_registration_test -- --nocapture`
|
|
||||||
- `./scripts/check_architecture_migration_rules.sh`
|
- `./scripts/check_architecture_migration_rules.sh`
|
||||||
- `./scripts/check_layer_dependencies.sh`
|
- `./scripts/check_layer_dependencies.sh`
|
||||||
- `./scripts/check_metrics_migration_refs.sh`
|
- `./scripts/check_metrics_migration_refs.sh`
|
||||||
- `git diff --check`
|
- `git diff --check`
|
||||||
- temporary negative check for an unaccounted admin route registration
|
|
||||||
- `make pre-commit`
|
- `make pre-commit`
|
||||||
|
|
||||||
## Handoff Notes
|
## Handoff Notes
|
||||||
|
|
||||||
- Keep Phase 0 PRs small. Do not move Config, Storage API, Runtime, or ECStore
|
- Keep this Phase 1 branch as a pure `contract` PR. Do not add
|
||||||
code inside this `test-only` branch.
|
`rustfs/src/admin` integration, route registration changes, auth enforcement,
|
||||||
- Route matrix instrumentation must remain test-only and must not alter dispatch
|
Config moves, Storage API moves, Runtime moves, or ECStore moves.
|
||||||
or auth behavior.
|
- The new crate is allowed to depend on generic Rust libraries such as
|
||||||
|
`thiserror`, but must stay independent from implementation crates and runtime
|
||||||
|
state.
|
||||||
- Do not add temporary compatibility code without a matching
|
- Do not add temporary compatibility code without a matching
|
||||||
`RUSTFS_COMPAT_TODO(<task-id>)` marker and cleanup-register entry.
|
`RUSTFS_COMPAT_TODO(<task-id>)` marker and cleanup-register entry.
|
||||||
- The next config-model PR must preserve the current tuple-struct shapes and
|
- The next admin route policy PR may consume the contract types, but must
|
||||||
persistence behavior before introducing narrower provider contracts.
|
preserve current route registration, alias canonicalization, public
|
||||||
- Do not move `config::com` until a dedicated helper-user inventory covers
|
exceptions, and handler-level authorization behavior.
|
||||||
ECStore-internal persistence paths as well as adjacent non-model users.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user