From 9c06a4ef6adc2bf191f5856cc85fbb4ce3c5bdaa Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Fri, 17 Jul 2026 16:19:37 +0100 Subject: [PATCH] docs: update audit spec references --- grasp-audit/src/result.rs | 14 +-- .../src/specs/grasp01/spec_requirements.rs | 96 +++++++++---------- .../src/specs/grasp06/spec_requirements.rs | 36 +++---- 3 files changed, 73 insertions(+), 73 deletions(-) diff --git a/grasp-audit/src/result.rs b/grasp-audit/src/result.rs index a7a0b27..01474b9 100644 --- a/grasp-audit/src/result.rs +++ b/grasp-audit/src/result.rs @@ -24,8 +24,8 @@ const BOLD: &str = "\x1b[1m"; /// Returns a vector of line numbers that this spec_ref covers /// /// Examples: -/// - "GRASP-01:nostr-relay:7" -> [7] -/// - "GRASP-01:nostr-relay:7-9" -> [7, 8, 9] +/// - "GRASP-01:nostr-relay:5" -> [5] +/// - "GRASP-01:nostr-relay:5-7" -> [5, 6, 7] /// - "NIP-01:basic:2" -> [] (not a GRASP-01 ref) fn parse_spec_lines(spec_ref: &str) -> Vec { // Only parse GRASP-01 refs @@ -444,16 +444,16 @@ mod tests { #[test] fn test_parse_spec_lines_single() { - assert_eq!(parse_spec_lines("GRASP-01:nostr-relay:7"), vec![7]); - assert_eq!(parse_spec_lines("GRASP-01:git-http:34"), vec![34]); + assert_eq!(parse_spec_lines("GRASP-01:nostr-relay:5"), vec![5]); + assert_eq!(parse_spec_lines("GRASP-01:git-http:32"), vec![32]); } #[test] fn test_parse_spec_lines_range() { - assert_eq!(parse_spec_lines("GRASP-01:nostr-relay:7-9"), vec![7, 8, 9]); + assert_eq!(parse_spec_lines("GRASP-01:nostr-relay:5-7"), vec![5, 6, 7]); assert_eq!( - parse_spec_lines("GRASP-01:cors:50-53"), - vec![50, 51, 52, 53] + parse_spec_lines("GRASP-01:cors:48-51"), + vec![48, 49, 50, 51] ); } diff --git a/grasp-audit/src/specs/grasp01/spec_requirements.rs b/grasp-audit/src/specs/grasp01/spec_requirements.rs index 85866a3..7a69b15 100644 --- a/grasp-audit/src/specs/grasp01/spec_requirements.rs +++ b/grasp-audit/src/specs/grasp01/spec_requirements.rs @@ -4,7 +4,7 @@ //! This is the single source of truth for spec text displayed in audit reports. /// GRASP spec repository commit ID that this version is based on -pub const GRASP_COMMIT_ID: &str = "1fdb8f7"; +pub const GRASP_COMMIT_ID: &str = "4eeee96ffefeec8fd80a320d944f5b5e89171f0b"; /// Reference to a specific GRASP-01 specification requirement #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -68,26 +68,26 @@ impl SpecRef { /// Get the spec reference string in format "GRASP-01:section:line" pub fn spec_ref_string(self) -> &'static str { match self { - SpecRef::NostrRelayNip01Compliant => "GRASP-01:nostr-relay:7", - SpecRef::NostrRelayRejectMissingCloneRelays => "GRASP-01:nostr-relay:9", - SpecRef::NostrRelayMayRejectOtherCriteria => "GRASP-01:nostr-relay:11", - SpecRef::NostrRelayMustAcceptTaggedEvents => "GRASP-01:nostr-relay:13", - SpecRef::NostrRelayMayRejectSpamCuration => "GRASP-01:nostr-relay:18", - SpecRef::PurgatoryAcceptUntilGitData => "GRASP-01:purgatory:22", - SpecRef::Nip11ServeDocument => "GRASP-01:nip-11:26", - SpecRef::Nip11ListSupportedGrasps => "GRASP-01:nip-11:28", - SpecRef::Nip11ListRepoAcceptanceCriteria => "GRASP-01:nip-11:29", - SpecRef::Nip11ListCurationPolicy => "GRASP-01:nip-11:30", - SpecRef::GitServeRepository => "GRASP-01:git-http:34", - SpecRef::GitAcceptPushesAlignState => "GRASP-01:git-http:36", - SpecRef::GitSetHeadOnReceive => "GRASP-01:git-http:39", - SpecRef::GitAcceptRefsNostrEventId => "GRASP-01:git-http:45", - SpecRef::GitIncludeAllowSha1InWant => "GRASP-01:git-http:56", - SpecRef::GitServeWebpage => "GRASP-01:git-http:58", - SpecRef::CorsAllowOrigin => "GRASP-01:cors:64", - SpecRef::CorsAllowMethods => "GRASP-01:cors:65", - SpecRef::CorsAllowHeaders => "GRASP-01:cors:66", - SpecRef::CorsOptionsResponse => "GRASP-01:cors:67", + SpecRef::NostrRelayNip01Compliant => "GRASP-01:nostr-relay:5", + SpecRef::NostrRelayRejectMissingCloneRelays => "GRASP-01:nostr-relay:7", + SpecRef::NostrRelayMayRejectOtherCriteria => "GRASP-01:nostr-relay:9", + SpecRef::NostrRelayMustAcceptTaggedEvents => "GRASP-01:nostr-relay:11", + SpecRef::NostrRelayMayRejectSpamCuration => "GRASP-01:nostr-relay:16", + SpecRef::PurgatoryAcceptUntilGitData => "GRASP-01:purgatory:20", + SpecRef::Nip11ServeDocument => "GRASP-01:nip-11:24", + SpecRef::Nip11ListSupportedGrasps => "GRASP-01:nip-11:26", + SpecRef::Nip11ListRepoAcceptanceCriteria => "GRASP-01:nip-11:27", + SpecRef::Nip11ListCurationPolicy => "GRASP-01:nip-11:28", + SpecRef::GitServeRepository => "GRASP-01:git-http:32", + SpecRef::GitAcceptPushesAlignState => "GRASP-01:git-http:34", + SpecRef::GitSetHeadOnReceive => "GRASP-01:git-http:36", + SpecRef::GitAcceptRefsNostrEventId => "GRASP-01:git-http:38", + SpecRef::GitIncludeAllowSha1InWant => "GRASP-01:git-http:40", + SpecRef::GitServeWebpage => "GRASP-01:git-http:42", + SpecRef::CorsAllowOrigin => "GRASP-01:cors:48", + SpecRef::CorsAllowMethods => "GRASP-01:cors:49", + SpecRef::CorsAllowHeaders => "GRASP-01:cors:50", + SpecRef::CorsOptionsResponse => "GRASP-01:cors:51", } } } @@ -103,70 +103,70 @@ pub const GRASP_01_REQUIREMENTS: &[SpecRequirement] = &[ // Nostr Relay section SpecRequirement { spec_ref: SpecRef::NostrRelayNip01Compliant, - line: 7, + line: 5, section: "Nostr Relay", text: "MUST serve a NIP-01 compliant nostr relay at `/` that accepts git repository announcements and their corresponding repo state announcements.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::NostrRelayRejectMissingCloneRelays, - line: 9, + line: 7, section: "Nostr Relay", text: "MUST reject git repository announcements that do not list the service in both `clone` and `relays` tags unless implementing `GRASP-05`.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::NostrRelayMayRejectOtherCriteria, - line: 11, + line: 9, section: "Nostr Relay", text: "MAY reject git repository announcements based on other criteria such as pre-payment, quotas, WoT, whitelist, SPAM prevention, etc.", level: RequirementLevel::May, }, SpecRequirement { spec_ref: SpecRef::NostrRelayMustAcceptTaggedEvents, - line: 13, + line: 11, section: "Nostr Relay", text: "MUST accept other events that tag, or are tagged by, either: 1. accepted git repository announcements; or 2. accepted issues or patches", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::NostrRelayMayRejectSpamCuration, - line: 18, + line: 16, section: "Nostr Relay", text: "MAY reject or delete events for generic SPAM prevention reasons or curation eg. WoT, whitelist, user bans and banned topics.", level: RequirementLevel::May, }, SpecRequirement { spec_ref: SpecRef::PurgatoryAcceptUntilGitData, - line: 22, + line: 20, section: "Purgatory", - text: "New repository announcements, repo state announcements, PRs and PR Updates SHOULD be accepted with message \"purgatory: won't be served until git data arrives\" and kept in purgatory (not served) until the related git data arrives and otherwise discarded after 30 minutes.", + text: "Accepted repo state announcements, PRs and PR Updates SHOULD be accepted with message \"purgatory: won't be served until git data arrives\" and kept in purgatory (not served) until the related git data arrives and otherwise discarded after 30 minutes.", level: RequirementLevel::Should, }, SpecRequirement { spec_ref: SpecRef::Nip11ServeDocument, - line: 26, + line: 24, section: "NIP-11", text: "MUST serve a NIP-11 document", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::Nip11ListSupportedGrasps, - line: 28, + line: 26, section: "NIP-11", text: "MUST list each supported GRASP under `supported_grasps` in format `GRASP-XX` eg `GRASP-01` as a string array", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::Nip11ListRepoAcceptanceCriteria, - line: 29, + line: 27, section: "NIP-11", text: "MUST list repository acceptance criteria under `repo_acceptance_criteria` as a human readable string", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::Nip11ListCurationPolicy, - line: 30, + line: 28, section: "NIP-11", text: "MUST list brief summary of curation policy under `curation` if events are curated beyond generic SPAM prevention; otherwise `curation` MUST be omitted", level: RequirementLevel::Must, @@ -174,42 +174,42 @@ pub const GRASP_01_REQUIREMENTS: &[SpecRequirement] = &[ // Git Smart HTTP Service section SpecRequirement { spec_ref: SpecRef::GitServeRepository, - line: 34, + line: 32, section: "Git Smart HTTP Service", - text: "MUST serve a git repository via an unauthenticated git smart http service at `//.git` for each git repository announcement the relay serves or has in purgatory.", + text: "MUST serve a git repository via an unauthenticated git smart http service at `//.git` for each accepted git repository announcement.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::GitAcceptPushesAlignState, - line: 36, + line: 34, section: "Git Smart HTTP Service", - text: "MUST accept pushes via this service that fully align the git repository state with a repo state announcement in purgatory that is authorised for this repository, respecting the recursive maintainer set.", + text: "MUST accept pushes via this service that match the latest repo state announcement on the relay, respecting the recursive maintainer set.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::GitSetHeadOnReceive, - line: 39, + line: 36, section: "Git Smart HTTP Service", - text: "As soon as the `receive-pack` is successful, the server MUST: 1. Release the event (and related repository announcement) from purgatory. 2. Align the repository HEAD with the repo state announcement. 3. Synchronize git state with other git repositories on the server for which this state event is authoritative.", + text: "MUST set repository HEAD per repo state announcement as soon as the git data related to that branch has been received.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::GitAcceptRefsNostrEventId, - line: 45, + line: 38, section: "Git Smart HTTP Service", text: "MUST accept pushes via this service to `refs/nostr/` but SHOULD reject if the event exists in purgatory listing a different tip, and MAY reject based on criteria such as size, SPAM prevention, etc.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::GitIncludeAllowSha1InWant, - line: 56, + line: 40, section: "Git Smart HTTP Service", - text: "MUST include `allow-reachable-sha1-in-want` and `allow-tip-sha1-in-want` in advertisement and serve available oids.", + text: "MUST include `allow-reachable-sha1-in-want`, `allow-tip-sha1-in-want`, and `uploadpack.allowFilter` in advertisement and serve available oids and filtered requests.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::GitServeWebpage, - line: 58, + line: 42, section: "Git Smart HTTP Service", text: "SHOULD serve a webpage at the same endpoint linking to git nostr client(s) to browse the repository and a 404 page for repositories it doesn't host.", level: RequirementLevel::Should, @@ -217,28 +217,28 @@ pub const GRASP_01_REQUIREMENTS: &[SpecRequirement] = &[ // CORS Support section SpecRequirement { spec_ref: SpecRef::CorsAllowOrigin, - line: 64, + line: 48, section: "CORS Support", text: "Set `Access-Control-Allow-Origin: *` on ALL responses", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::CorsAllowMethods, - line: 65, + line: 49, section: "CORS Support", text: "Set `Access-Control-Allow-Methods: GET, POST` on ALL responses", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::CorsAllowHeaders, - line: 66, + line: 50, section: "CORS Support", text: "Set `Access-Control-Allow-Headers: Content-Type` on ALL responses", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::CorsOptionsResponse, - line: 67, + line: 51, section: "CORS Support", text: "Respond to OPTIONS requests with 204 No Content", level: RequirementLevel::Must, @@ -282,7 +282,7 @@ mod tests { #[test] fn test_get_requirement() { - let req = get_requirement(7).expect("Line 7 should exist"); + let req = get_requirement(5).expect("Line 5 should exist"); assert_eq!(req.section, "Nostr Relay"); assert!(req.text.contains("NIP-01")); } @@ -291,7 +291,7 @@ mod tests { fn test_get_requirement_by_ref() { let req = get_requirement_by_ref(SpecRef::NostrRelayNip01Compliant) .expect("SpecRef should exist"); - assert_eq!(req.line, 7); + assert_eq!(req.line, 5); assert_eq!(req.spec_ref, SpecRef::NostrRelayNip01Compliant); } diff --git a/grasp-audit/src/specs/grasp06/spec_requirements.rs b/grasp-audit/src/specs/grasp06/spec_requirements.rs index 0085de9..ba9a9e6 100644 --- a/grasp-audit/src/specs/grasp06/spec_requirements.rs +++ b/grasp-audit/src/specs/grasp06/spec_requirements.rs @@ -11,7 +11,7 @@ use crate::specs::grasp01::RequirementLevel; /// /// Update this when bumping to a newer spec revision so reports indicate /// which spec line numbers are being referenced. -pub const GRASP_06_COMMIT_ID: &str = "DRAFT"; +pub const GRASP_06_COMMIT_ID: &str = "4eeee96ffefeec8fd80a320d944f5b5e89171f0b"; /// Reference to a specific GRASP-06 specification requirement. /// @@ -27,18 +27,18 @@ pub enum SpecRef { /// configured with GRASP-06 enabled, NIP-11 `supported_grasps` MUST /// include `"GRASP-06"` so clients can discover the capability. Grasp06AdvertisedWhenEnabled, - /// 06.md line 13 — MUST respond to upload-pack on any well-formed path as + /// 06.md line 11 — MUST respond to upload-pack on any well-formed path as /// if serving an empty bare repository. Grasp06FetchEmptyRepo, - /// 06.md line 15 — MUST accept pushes to `refs/nostr/`. + /// 06.md line 13 — MUST accept pushes to `refs/nostr/`. Grasp06AcceptRefsNostrPush, - /// 06.md line 15 — MUST reject pushes to any other ref namespace. + /// 06.md line 13 — MUST reject pushes to any other ref namespace. Grasp06RejectNonNostrRefs, - /// 06.md lines 21–24 — MUST accept PR/PR-Update events that would otherwise + /// 06.md lines 19–22 — MUST accept PR/PR-Update events that would otherwise /// be rejected by GRASP-01, when they carry a matching `a` tag AND a `clone` /// tag naming this relay's /prs/ endpoint. Grasp06RelaxAcceptPrEvent, - /// 06.md lines 23–24 — the relaxation applies only when the event's `clone` + /// 06.md line 22 — the relaxation applies only when the event's `clone` /// tag names this relay's /prs/ endpoint; otherwise the event is rejected. Grasp06RelaxRequiresCloneTag, /// Design-doc derived (docs/explanation/grasp-06-contributor-pr-submission.md @@ -79,11 +79,11 @@ impl SpecRef { match self { SpecRef::Grasp06NotAdvertised404 => "GRASP-06:nip-11-discovery:-1", SpecRef::Grasp06AdvertisedWhenEnabled => "GRASP-06:nip-11-discovery:-2", - SpecRef::Grasp06FetchEmptyRepo => "GRASP-06:git-http:13", - SpecRef::Grasp06AcceptRefsNostrPush => "GRASP-06:git-http-accept:15", - SpecRef::Grasp06RejectNonNostrRefs => "GRASP-06:git-http-reject:15", - SpecRef::Grasp06RelaxAcceptPrEvent => "GRASP-06:event-acceptance:21", - SpecRef::Grasp06RelaxRequiresCloneTag => "GRASP-06:event-acceptance:23", + SpecRef::Grasp06FetchEmptyRepo => "GRASP-06:git-http:11", + SpecRef::Grasp06AcceptRefsNostrPush => "GRASP-06:git-http-accept:13", + SpecRef::Grasp06RejectNonNostrRefs => "GRASP-06:git-http-reject:13", + SpecRef::Grasp06RelaxAcceptPrEvent => "GRASP-06:event-acceptance:19", + SpecRef::Grasp06RelaxRequiresCloneTag => "GRASP-06:event-acceptance:22", SpecRef::Grasp06MirrorToAnnouncedRepo => "GRASP-06:mirror-forward:design", SpecRef::Grasp06NoReverseMirror => "GRASP-06:mirror-reverse:design", SpecRef::Grasp06CommitMismatchDeletesRef => "GRASP-06:commit-mismatch:design", @@ -133,21 +133,21 @@ pub const GRASP_06_REQUIREMENTS: &[SpecRequirement] = &[ // Git Smart HTTP Service SpecRequirement { spec_ref: SpecRef::Grasp06FetchEmptyRepo, - line: 13, + line: 11, section: "Git Smart HTTP Service", text: "MUST respond to upload-pack requests for any well-formed path as if serving an empty bare repository until at least one `refs/nostr/` has been accepted for that path.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::Grasp06AcceptRefsNostrPush, - line: 15, + line: 13, section: "Git Smart HTTP Service", text: "MUST accept pushes to `refs/nostr/`. MAY reject based on size, SPAM prevention, allowlists, pre-payment, PoW, or similar policy.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::Grasp06RejectNonNostrRefs, - line: 15, + line: 13, section: "Git Smart HTTP Service", text: "MUST reject pushes to any other ref namespace (only `refs/nostr/` is accepted).", level: RequirementLevel::Must, @@ -155,14 +155,14 @@ pub const GRASP_06_REQUIREMENTS: &[SpecRequirement] = &[ // Event Acceptance SpecRequirement { spec_ref: SpecRef::Grasp06RelaxAcceptPrEvent, - line: 21, + line: 19, section: "Event Acceptance", text: "MUST accept PRs and PR Updates that would otherwise be rejected under GRASP-01 for not referencing an accepted repository announcement, provided the event has an `a` tag of the form `30617::` AND a `clone` tag naming this service's /prs//.git endpoint.", level: RequirementLevel::Must, }, SpecRequirement { spec_ref: SpecRef::Grasp06RelaxRequiresCloneTag, - line: 23, + line: 22, section: "Event Acceptance", text: "The relaxation applies ONLY when the event's `clone` tag names this relay's /prs/ endpoint. PR events without a matching clone tag remain subject to GRASP-01 rejection.", level: RequirementLevel::Must, @@ -240,8 +240,8 @@ mod tests { #[test] fn test_parse_spec_line_real() { + assert_eq!(parse_spec_line("GRASP-06:git-http:11"), Some(11)); assert_eq!(parse_spec_line("GRASP-06:git-http:13"), Some(13)); - assert_eq!(parse_spec_line("GRASP-06:git-http:15"), Some(15)); } #[test] @@ -251,7 +251,7 @@ mod tests { #[test] fn test_parse_spec_line_non_grasp06() { - assert_eq!(parse_spec_line("GRASP-01:nostr-relay:7"), None); + assert_eq!(parse_spec_line("GRASP-01:nostr-relay:5"), None); assert_eq!(parse_spec_line("NIP-01:basic:1"), None); }