refactor(server): fold in PM review notes on classify_path

- classify_path now Rejects a collection slug containing '.' (mirrors
  OrgCollections::validate, plan L317, and item_path's documented contract,
  plan L990). Unreachable today since git normalizes './' away, but keeps the
  pre-receive hook self-defensive against path traversal.
- Rename test item_write_nested_slug_takes_leading_segment_only ->
  item_write_nested_slug_is_rejected (it asserts Rejected; old name misled).
- Add dotted_slug_is_rejected covering the new guard.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01M5brcDrT35r5GaJySXD5ja
This commit is contained in:
adlee-was-taken
2026-06-19 23:06:48 -04:00
parent 675b7836e1
commit 2dd5d79f36
2 changed files with 19 additions and 2 deletions

View File

@@ -18,8 +18,8 @@ fn item_write_yields_collection_slug() {
}
#[test]
fn item_write_nested_slug_takes_leading_segment_only() {
// Slugs cannot contain '/', so a 4-segment path is malformed → Rejected.
fn item_write_nested_slug_is_rejected() {
// Slugs cannot contain '/', so a path with extra segments is malformed → Rejected.
assert_eq!(
classify_path("items/prod/sub/x.enc"),
PathClass::Rejected("items path must be items/<slug>/<id>.enc".to_string())
@@ -51,6 +51,16 @@ fn empty_slug_segment_is_rejected() {
);
}
#[test]
fn dotted_slug_is_rejected() {
// Defense-in-depth (mirrors OrgCollections::validate): a slug containing '.'
// — e.g. a ".."/"." path-traversal attempt — is rejected.
assert_eq!(
classify_path("items/../x.enc"),
PathClass::Rejected("invalid collection slug: \"..\"".to_string())
);
}
use relicario_server::extract_schema_version;
#[test]