diff --git a/docs/design-plans/2026-04-16-test-oauth-client.md b/docs/design-plans/2026-04-16-test-oauth-client.md index deb463a..06f203d 100644 --- a/docs/design-plans/2026-04-16-test-oauth-client.md +++ b/docs/design-plans/2026-04-16-test-oauth-client.md @@ -90,6 +90,7 @@ conformance, and any operational deployment of a hosted helper service - **test-oauth-client.AC2.7 Failure:** A native client whose `redirect_uri` scheme does not match the reverse-domain of the `client_id` host produces a `SpecViolation`. - **test-oauth-client.AC2.7b Failure:** A native client whose custom-scheme `redirect_uri` uses `scheme://host/path` rather than the spec-required `scheme:/path` (single colon, single forward slash, no authority) produces a `SpecViolation` on `redirect_uris_shape`. See : *"The URI scheme must be followed by a single colon (`:`) then a single forward slash (`/`) and then a URI path component."* - **test-oauth-client.AC2.7c Failure:** Any HTTPS `redirect_uri` that explicitly declares the default port (`:443`) produces a `SpecViolation` on `redirect_uris_shape`. The atproto OAuth profile restates the OAuth 2.0 rule: *"The URL may include a port number, but not if it is the default port number."* Applies to web and native HTTPS redirects alike. +- **test-oauth-client.AC2.8a Failure:** A `client_uri` whose hostname differs from `client_id`'s hostname produces a `SpecViolation` on `client_uri_host_matches_client_id`. The spec () states: *"`client_uri` … must have the same hostname as `client_id`."* The field is optional overall, so when absent the check emits `Skipped` with reason `"`client_uri` not declared"`. - **test-oauth-client.AC2.8 Failure:** A `scope` field that does not parse against the atproto permission grammar () produces a `SpecViolation` with the offending token highlighted via miette source span. The grammar is `[:][?]`; all three bracketed components are optional independently, so `repo` (bare), `repo:app.bsky.feed.post` (positional only), `repo?collection=foo` (query only), and `repo:app.bsky.feed.post?action=create` (both) are all valid. The resource name is **not** constrained to a fixed set — the spec states it will expand over time and defines `transition:generic`, `transition:chat.bsky`, and `transition:email` as migration-period resources, so the grammar check only flags genuinely syntactic failures (empty resource, malformed `key=value` query pairs, invalid percent-encoding). Unknown-but-well-formed resource names are accepted. - **test-oauth-client.AC2.9 Skip:** Every metadata-document validation check on a loopback target emits `Skipped` with reason `"metadata is implicit for loopback clients"`. diff --git a/src/commands/test/oauth/client/pipeline/metadata.rs b/src/commands/test/oauth/client/pipeline/metadata.rs index 88833bd..57df6ee 100644 --- a/src/commands/test/oauth/client/pipeline/metadata.rs +++ b/src/commands/test/oauth/client/pipeline/metadata.rs @@ -32,6 +32,7 @@ pub struct RawMetadataDocument { /// Stored as raw JSON; Phase 5 parses it into JWK format. pub jwks: Option, pub jwks_uri: Option, + pub client_uri: Option, } /// Parse a metadata document from raw bytes. @@ -419,6 +420,17 @@ pub enum Check { /// token fails the check with a span pointing at the offending /// token. ScopeGrammarValid, + /// `client_uri`, if present, has the same hostname as `client_id`. + /// The atproto OAuth profile + /// () states: + /// *"`client_uri` (string, optional): … must have the same + /// hostname as `client_id`."* When absent, the check emits + /// `Skipped`. This deters metadata documents that point + /// `client_uri` at an unrelated domain — one of the spec's + /// stated concerns is that untrusted users may upload client + /// metadata to arbitrary URLs and use these fields for + /// impersonation. + ClientUriHostMatchesClientId, } impl Check { @@ -447,6 +459,9 @@ impl Check { Check::ScopePresent => "oauth_client::metadata::scope_present", Check::ScopeIncludesAtproto => "oauth_client::metadata::scope_includes_atproto", Check::ScopeGrammarValid => "oauth_client::metadata::scope_grammar", + Check::ClientUriHostMatchesClientId => { + "oauth_client::metadata::client_uri_host_matches_client_id" + } } } @@ -481,6 +496,7 @@ impl Check { Check::ScopePresent => "`scope` field is present", Check::ScopeIncludesAtproto => "`scope` includes the `atproto` token", Check::ScopeGrammarValid => "`scope` parses against the atproto permission grammar", + Check::ClientUriHostMatchesClientId => "`client_uri` hostname matches `client_id`", } } @@ -530,6 +546,7 @@ pub const CHECK_ALL: &[Check] = &[ Check::ScopePresent, Check::ScopeIncludesAtproto, Check::ScopeGrammarValid, + Check::ClientUriHostMatchesClientId, ]; /// Output from the metadata validation stage. @@ -1141,6 +1158,66 @@ pub fn run( } }; + // Check ClientUriHostMatchesClientId. Per the + // atproto OAuth profile `client_uri` is optional + // but, if declared, must share `client_id`'s + // hostname. + match (doc.client_uri.as_deref(), parsed_client_id.as_ref()) { + (None, _) => { + results.push(skipped_with_reason( + Check::ClientUriHostMatchesClientId.id(), + Stage::OAUTH_CLIENT_METADATA, + Check::ClientUriHostMatchesClientId.summary(), + "`client_uri` not declared", + )); + } + (Some(_), None) => { + results.push(blocked_by( + Check::ClientUriHostMatchesClientId.id(), + Stage::OAUTH_CLIENT_METADATA, + Check::ClientUriHostMatchesClientId.summary(), + Check::ClientIdMatches.id(), + )); + } + (Some(client_uri_str), Some(parsed_id)) => { + match Url::parse(client_uri_str) { + Err(_) => { + let diagnostic: Box = + Box::new(MetadataViolationDiagnostic { + message: format!( + "`client_uri` is not a valid URL: `{client_uri_str}`" + ), + code: "oauth_client::metadata::client_uri_host_matches_client_id", + }); + results.push( + Check::ClientUriHostMatchesClientId + .spec_violation(Some(diagnostic)), + ); + } + Ok(parsed_uri) => { + if parsed_uri.host() == parsed_id.host() { + results.push(Check::ClientUriHostMatchesClientId.pass()); + } else { + let diagnostic: Box = + Box::new(MetadataViolationDiagnostic { + message: format!( + "`client_uri` host (`{}`) does not match \ + `client_id` host (`{}`)", + parsed_uri.host_str().unwrap_or(""), + parsed_id.host_str().unwrap_or(""), + ), + code: "oauth_client::metadata::client_uri_host_matches_client_id", + }); + results.push( + Check::ClientUriHostMatchesClientId + .spec_violation(Some(diagnostic)), + ); + } + } + } + } + } + // Build MetadataFacts if we have enough information. let facts = if let (Some(kind), Some(client_id)) = (client_kind, parsed_client_id) { diff --git a/tests/fixtures/oauth_client/metadata/client_uri_host_mismatch/metadata.json b/tests/fixtures/oauth_client/metadata/client_uri_host_mismatch/metadata.json new file mode 100644 index 0000000..aa37db8 --- /dev/null +++ b/tests/fixtures/oauth_client/metadata/client_uri_host_mismatch/metadata.json @@ -0,0 +1,11 @@ +{ + "client_id": "https://client.example.com/metadata.json", + "application_type": "web", + "response_types": ["code"], + "grant_types": ["authorization_code"], + "scope": "atproto", + "redirect_uris": ["https://client.example.com/cb"], + "dpop_bound_access_tokens": true, + "token_endpoint_auth_method": "none", + "client_uri": "https://not-the-same.example.org/about" +} diff --git a/tests/oauth_client_check_id_coverage.rs b/tests/oauth_client_check_id_coverage.rs index 3d43f67..a5f9c2a 100644 --- a/tests/oauth_client_check_id_coverage.rs +++ b/tests/oauth_client_check_id_coverage.rs @@ -137,6 +137,7 @@ fn all_expected_diagnostic_codes() -> Vec<&'static str> { "oauth_client::metadata::redirect_scheme_reverse_domain_mismatch", "oauth_client::metadata::token_endpoint_auth_method_valid", "oauth_client::metadata::token_endpoint_auth_signing_alg_valid", + "oauth_client::metadata::client_uri_host_matches_client_id", // JWKS stage diagnostic codes. "oauth_client::jws::jwks_uri_unreachable", "oauth_client::jws::jwks_is_json", diff --git a/tests/oauth_client_metadata.rs b/tests/oauth_client_metadata.rs index 9a5837b..67a167b 100644 --- a/tests/oauth_client_metadata.rs +++ b/tests/oauth_client_metadata.rs @@ -582,6 +582,42 @@ async fn signing_alg_none_is_spec_violation() { insta::assert_snapshot!(rendered); } +/// Per : +/// "`client_uri` (string, optional): … must have the same hostname +/// as `client_id`." A `client_uri` whose host differs from the +/// `client_id` host fails `client_uri_host_matches_client_id`. +#[tokio::test] +async fn client_uri_host_mismatch_is_spec_violation() { + let http = common::FakeHttpClient::new(); + let metadata = + include_bytes!("fixtures/oauth_client/metadata/client_uri_host_mismatch/metadata.json"); + http.add_response( + &Url::parse("https://client.example.com/metadata.json").unwrap(), + 200, + metadata.to_vec(), + ); + + let target = target::parse("https://client.example.com/metadata.json").expect("parse failed"); + let jwks_fetcher = common::FakeJwksFetcher::new(); + let opts = OauthClientOptions { + interactive: None, + http: &http, + jwks: &jwks_fetcher, + verbose: false, + clock: Arc::new(RealClock), + }; + + let report = run_pipeline(target, opts).await; + assert_eq!( + report.exit_code(), + 1, + "client_uri host mismatch must be a SpecViolation" + ); + + let rendered = render_report_to_string(&report); + insta::assert_snapshot!(rendered); +} + /// Per : /// "The URL may include a port number, but not if it is the default /// port number." An HTTPS `redirect_uri` that explicitly declares diff --git a/tests/snapshots/oauth_client_discovery__https_404_produces_network_error.snap b/tests/snapshots/oauth_client_discovery__https_404_produces_network_error.snap index 0fbd7ab..e5ddc2c 100644 --- a/tests/snapshots/oauth_client_discovery__https_404_produces_network_error.snap +++ b/tests/snapshots/oauth_client_discovery__https_404_produces_network_error.snap @@ -30,6 +30,7 @@ Target: https://client.example.com/missing.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -39,4 +40,4 @@ Target: https://client.example.com/missing.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 25 skipped. Exit code: 2 +Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 26 skipped. Exit code: 2 diff --git a/tests/snapshots/oauth_client_discovery__https_confidential_happy_discovery.snap b/tests/snapshots/oauth_client_discovery__https_confidential_happy_discovery.snap index 5befaa0..5ddf6e1 100644 --- a/tests/snapshots/oauth_client_discovery__https_confidential_happy_discovery.snap +++ b/tests/snapshots/oauth_client_discovery__https_confidential_happy_discovery.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 0 +Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_discovery__https_not_json_produces_spec_violation.snap b/tests/snapshots/oauth_client_discovery__https_not_json_produces_spec_violation.snap index 26e2cb6..98c3a13 100644 --- a/tests/snapshots/oauth_client_discovery__https_not_json_produces_spec_violation.snap +++ b/tests/snapshots/oauth_client_discovery__https_not_json_produces_spec_violation.snap @@ -34,6 +34,7 @@ Target: https://client.example.com/metadata.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -43,4 +44,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 3 passed, 1 failed (spec), 0 network errors, 0 advisories, 23 skipped. Exit code: 1 +Summary: 3 passed, 1 failed (spec), 0 network errors, 0 advisories, 24 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_discovery__https_not_json_with_content_type_produces_spec_violation_with_ct.snap b/tests/snapshots/oauth_client_discovery__https_not_json_with_content_type_produces_spec_violation_with_ct.snap index 4fe12bc..331ed67 100644 --- a/tests/snapshots/oauth_client_discovery__https_not_json_with_content_type_produces_spec_violation_with_ct.snap +++ b/tests/snapshots/oauth_client_discovery__https_not_json_with_content_type_produces_spec_violation_with_ct.snap @@ -38,6 +38,7 @@ Target: https://client.example.com/metadata.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -47,4 +48,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 2 passed, 2 failed (spec), 0 network errors, 0 advisories, 23 skipped. Exit code: 1 +Summary: 2 passed, 2 failed (spec), 0 network errors, 0 advisories, 24 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_discovery__https_unreachable_produces_network_error.snap b/tests/snapshots/oauth_client_discovery__https_unreachable_produces_network_error.snap index 78faac2..732218f 100644 --- a/tests/snapshots/oauth_client_discovery__https_unreachable_produces_network_error.snap +++ b/tests/snapshots/oauth_client_discovery__https_unreachable_produces_network_error.snap @@ -30,6 +30,7 @@ Target: https://client.example.com/metadata.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -39,4 +40,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 25 skipped. Exit code: 2 +Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 26 skipped. Exit code: 2 diff --git a/tests/snapshots/oauth_client_discovery__loopback_root_produces_skip_rows.snap b/tests/snapshots/oauth_client_discovery__loopback_root_produces_skip_rows.snap index 3ac43a1..c0925c0 100644 --- a/tests/snapshots/oauth_client_discovery__loopback_root_produces_skip_rows.snap +++ b/tests/snapshots/oauth_client_discovery__loopback_root_produces_skip_rows.snap @@ -27,6 +27,7 @@ Target: http://localhost/ [SKIP] `scope` field is present — metadata is implicit for loopback clients [SKIP] `scope` includes the `atproto` token — metadata is implicit for loopback clients [SKIP] `scope` parses against the atproto permission grammar — metadata is implicit for loopback clients +[SKIP] `client_uri` hostname matches `client_id` — metadata is implicit for loopback clients == JWKS == [SKIP] JWKS is present — jwks not applicable to loopback clients [SKIP] JWKS URI is fetchable — jwks not applicable to loopback clients @@ -36,4 +37,4 @@ Target: http://localhost/ [SKIP] Keys use signing use — jwks not applicable to loopback clients [SKIP] Algorithms are modern EC — jwks not applicable to loopback clients -Summary: 1 passed, 0 failed (spec), 0 network errors, 0 advisories, 26 skipped. Exit code: 0 +Summary: 1 passed, 0 failed (spec), 0 network errors, 0 advisories, 27 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_endtoend__full_pipeline_all_pass.snap b/tests/snapshots/oauth_client_endtoend__full_pipeline_all_pass.snap index 7d8ae01..8d590e4 100644 --- a/tests/snapshots/oauth_client_endtoend__full_pipeline_all_pass.snap +++ b/tests/snapshots/oauth_client_endtoend__full_pipeline_all_pass.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 0 +Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_jwks__discovery_failure_blocks_jwks.snap b/tests/snapshots/oauth_client_jwks__discovery_failure_blocks_jwks.snap index 170bd29..6d16ebc 100644 --- a/tests/snapshots/oauth_client_jwks__discovery_failure_blocks_jwks.snap +++ b/tests/snapshots/oauth_client_jwks__discovery_failure_blocks_jwks.snap @@ -30,6 +30,7 @@ Target: https://client.example.com/metadata.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -39,4 +40,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 25 skipped. Exit code: 2 +Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 26 skipped. Exit code: 2 diff --git a/tests/snapshots/oauth_client_jwks__duplicate_kids_produces_spec_violation.snap b/tests/snapshots/oauth_client_jwks__duplicate_kids_produces_spec_violation.snap index a92af1f..bb650c7 100644 --- a/tests/snapshots/oauth_client_jwks__duplicate_kids_produces_spec_violation.snap +++ b/tests/snapshots/oauth_client_jwks__duplicate_kids_produces_spec_violation.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -44,4 +45,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_jwks__inline_es256_happy_jwks_passes.snap b/tests/snapshots/oauth_client_jwks__inline_es256_happy_jwks_passes.snap index 7d03189..9da59a4 100644 --- a/tests/snapshots/oauth_client_jwks__inline_es256_happy_jwks_passes.snap +++ b/tests/snapshots/oauth_client_jwks__inline_es256_happy_jwks_passes.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 0 +Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_jwks__loopback_skips_all_jwks.snap b/tests/snapshots/oauth_client_jwks__loopback_skips_all_jwks.snap index ae45b15..a309a2c 100644 --- a/tests/snapshots/oauth_client_jwks__loopback_skips_all_jwks.snap +++ b/tests/snapshots/oauth_client_jwks__loopback_skips_all_jwks.snap @@ -27,6 +27,7 @@ Target: http://localhost/ [SKIP] `scope` field is present — metadata is implicit for loopback clients [SKIP] `scope` includes the `atproto` token — metadata is implicit for loopback clients [SKIP] `scope` parses against the atproto permission grammar — metadata is implicit for loopback clients +[SKIP] `client_uri` hostname matches `client_id` — metadata is implicit for loopback clients == JWKS == [SKIP] JWKS is present — jwks not applicable to loopback clients [SKIP] JWKS URI is fetchable — jwks not applicable to loopback clients @@ -36,4 +37,4 @@ Target: http://localhost/ [SKIP] Keys use signing use — jwks not applicable to loopback clients [SKIP] Algorithms are modern EC — jwks not applicable to loopback clients -Summary: 1 passed, 0 failed (spec), 0 network errors, 0 advisories, 26 skipped. Exit code: 0 +Summary: 1 passed, 0 failed (spec), 0 network errors, 0 advisories, 27 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_jwks__public_client_skips_all_jwks.snap b/tests/snapshots/oauth_client_jwks__public_client_skips_all_jwks.snap index c510b3e..98c8353 100644 --- a/tests/snapshots/oauth_client_jwks__public_client_skips_all_jwks.snap +++ b/tests/snapshots/oauth_client_jwks__public_client_skips_all_jwks.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — jwks not required for public clients [SKIP] JWKS URI is fetchable — jwks not required for public clients @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — jwks not required for public clients [SKIP] Algorithms are modern EC — jwks not required for public clients -Summary: 18 passed, 0 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 0 +Summary: 18 passed, 0 failed (spec), 0 network errors, 0 advisories, 9 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_jwks__signing_alg_has_no_compatible_key_produces_spec_violation.snap b/tests/snapshots/oauth_client_jwks__signing_alg_has_no_compatible_key_produces_spec_violation.snap index efb7bbf..1d4ce5d 100644 --- a/tests/snapshots/oauth_client_jwks__signing_alg_has_no_compatible_key_produces_spec_violation.snap +++ b/tests/snapshots/oauth_client_jwks__signing_alg_has_no_compatible_key_produces_spec_violation.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_jwks__uri_es256_happy_jwks_passes.snap b/tests/snapshots/oauth_client_jwks__uri_es256_happy_jwks_passes.snap index 4d22ac6..af47cfe 100644 --- a/tests/snapshots/oauth_client_jwks__uri_es256_happy_jwks_passes.snap +++ b/tests/snapshots/oauth_client_jwks__uri_es256_happy_jwks_passes.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [OK] JWKS URI is fetchable @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 26 passed, 0 failed (spec), 0 network errors, 0 advisories, 0 skipped. Exit code: 0 +Summary: 26 passed, 0 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_jwks__uri_invalid_json_produces_spec_violation.snap b/tests/snapshots/oauth_client_jwks__uri_invalid_json_produces_spec_violation.snap index 9879d32..2863fa1 100644 --- a/tests/snapshots/oauth_client_jwks__uri_invalid_json_produces_spec_violation.snap +++ b/tests/snapshots/oauth_client_jwks__uri_invalid_json_produces_spec_violation.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [OK] JWKS URI is fetchable @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::jws::jwks_is_json [SKIP] Algorithms are modern EC — blocked by oauth_client::jws::jwks_is_json -Summary: 21 passed, 1 failed (spec), 0 network errors, 0 advisories, 4 skipped. Exit code: 1 +Summary: 21 passed, 1 failed (spec), 0 network errors, 0 advisories, 5 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_jwks__uri_returns_404_produces_network_error.snap b/tests/snapshots/oauth_client_jwks__uri_returns_404_produces_network_error.snap index 61453ea..5b2c3d3 100644 --- a/tests/snapshots/oauth_client_jwks__uri_returns_404_produces_network_error.snap +++ b/tests/snapshots/oauth_client_jwks__uri_returns_404_produces_network_error.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [NET] JWKS URI is fetchable @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::jws::jwks_uri_fetchable [SKIP] Algorithms are modern EC — blocked by oauth_client::jws::jwks_uri_fetchable -Summary: 20 passed, 0 failed (spec), 1 network errors, 0 advisories, 5 skipped. Exit code: 2 +Summary: 20 passed, 0 failed (spec), 1 network errors, 0 advisories, 6 skipped. Exit code: 2 diff --git a/tests/snapshots/oauth_client_jwks__uri_unreachable_produces_network_error.snap b/tests/snapshots/oauth_client_jwks__uri_unreachable_produces_network_error.snap index 43c1a89..343c562 100644 --- a/tests/snapshots/oauth_client_jwks__uri_unreachable_produces_network_error.snap +++ b/tests/snapshots/oauth_client_jwks__uri_unreachable_produces_network_error.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [NET] JWKS URI is fetchable @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::jws::jwks_uri_fetchable [SKIP] Algorithms are modern EC — blocked by oauth_client::jws::jwks_uri_fetchable -Summary: 20 passed, 0 failed (spec), 1 network errors, 0 advisories, 5 skipped. Exit code: 2 +Summary: 20 passed, 0 failed (spec), 1 network errors, 0 advisories, 6 skipped. Exit code: 2 diff --git a/tests/snapshots/oauth_client_jwks__weak_alg_rs1_produces_spec_violation.snap b/tests/snapshots/oauth_client_jwks__weak_alg_rs1_produces_spec_violation.snap index 0328e62..12e1124 100644 --- a/tests/snapshots/oauth_client_jwks__weak_alg_rs1_produces_spec_violation.snap +++ b/tests/snapshots/oauth_client_jwks__weak_alg_rs1_produces_spec_violation.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -41,4 +42,4 @@ Target: https://client.example.com/metadata.json × One or more keys declare non-modern algorithms -Summary: 23 passed, 2 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 23 passed, 2 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_jwks__wrong_use_produces_spec_violation.snap b/tests/snapshots/oauth_client_jwks__wrong_use_produces_spec_violation.snap index c9ecc87..714664a 100644 --- a/tests/snapshots/oauth_client_jwks__wrong_use_produces_spec_violation.snap +++ b/tests/snapshots/oauth_client_jwks__wrong_use_produces_spec_violation.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json × One or more keys have `use` other than `sig` [OK] Algorithms are modern EC -Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__application_type_omitted_defaults_to_web.snap b/tests/snapshots/oauth_client_metadata__application_type_omitted_defaults_to_web.snap index e84884b..a53d10a 100644 --- a/tests/snapshots/oauth_client_metadata__application_type_omitted_defaults_to_web.snap +++ b/tests/snapshots/oauth_client_metadata__application_type_omitted_defaults_to_web.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — jwks not required for public clients [SKIP] JWKS URI is fetchable — jwks not required for public clients @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — jwks not required for public clients [SKIP] Algorithms are modern EC — jwks not required for public clients -Summary: 17 passed, 0 failed (spec), 0 network errors, 0 advisories, 9 skipped. Exit code: 0 +Summary: 17 passed, 0 failed (spec), 0 network errors, 0 advisories, 10 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_metadata__client_uri_host_mismatch_is_spec_violation.snap b/tests/snapshots/oauth_client_metadata__client_uri_host_mismatch_is_spec_violation.snap new file mode 100644 index 0000000..e85cb89 --- /dev/null +++ b/tests/snapshots/oauth_client_metadata__client_uri_host_mismatch_is_spec_violation.snap @@ -0,0 +1,42 @@ +--- +source: tests/oauth_client_metadata.rs +expression: rendered +--- +Target: https://client.example.com/metadata.json + elapsed: XXms + +== Discovery == +[OK] Client ID well-formed +[OK] Metadata document fetchable +[OK] Metadata Content-Type is JSON +[OK] Metadata is valid JSON +== Metadata == +[OK] Metadata document deserializes +[OK] Metadata `client_id` matches fetched URL +[OK] `application_type` field is present +[OK] `application_type` is `web` or `native` +[OK] `response_types` includes `code` +[OK] `grant_types` includes `authorization_code` +[OK] `dpop_bound_access_tokens` is `true` +[OK] `redirect_uris` is non-empty +[OK] Every `redirect_uri` has the right shape for the client kind +[OK] `token_endpoint_auth_method` matches client kind +[SKIP] `token_endpoint_auth_signing_alg` is not `none` — `token_endpoint_auth_signing_alg` not declared +[OK] Public/native client does not provide `jwks` or `jwks_uri` +[OK] `scope` field is present +[OK] `scope` includes the `atproto` token +[OK] `scope` parses against the atproto permission grammar +[FAIL] `client_uri` hostname matches `client_id` + oauth_client::metadata::client_uri_host_matches_client_id + + × `client_uri` host (`not-the-same.example.org`) does not match `client_id` host (`client.example.com`) +== JWKS == +[SKIP] JWKS is present — jwks not required for public clients +[SKIP] JWKS URI is fetchable — jwks not required for public clients +[SKIP] JWKS is valid JSON — jwks not required for public clients +[SKIP] Keys have unique kid values — jwks not required for public clients +[SKIP] JWKS contains a key compatible with `token_endpoint_auth_signing_alg` — jwks not required for public clients +[SKIP] Keys use signing use — jwks not required for public clients +[SKIP] Algorithms are modern EC — jwks not required for public clients + +Summary: 18 passed, 1 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__confidential_happy.snap b/tests/snapshots/oauth_client_metadata__confidential_happy.snap index e5523c0..508a3fa 100644 --- a/tests/snapshots/oauth_client_metadata__confidential_happy.snap +++ b/tests/snapshots/oauth_client_metadata__confidential_happy.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 0 +Summary: 25 passed, 0 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_metadata__confidential_missing_jwks.snap b/tests/snapshots/oauth_client_metadata__confidential_missing_jwks.snap index c05e93d..10bc682 100644 --- a/tests/snapshots/oauth_client_metadata__confidential_missing_jwks.snap +++ b/tests/snapshots/oauth_client_metadata__confidential_missing_jwks.snap @@ -29,6 +29,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::confidential_requires_jwks [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::confidential_requires_jwks @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::confidential_requires_jwks [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::confidential_requires_jwks -Summary: 18 passed, 1 failed (spec), 0 network errors, 0 advisories, 7 skipped. Exit code: 1 +Summary: 18 passed, 1 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__discovery_failure_blocks_metadata.snap b/tests/snapshots/oauth_client_metadata__discovery_failure_blocks_metadata.snap index 00fded5..dc024c3 100644 --- a/tests/snapshots/oauth_client_metadata__discovery_failure_blocks_metadata.snap +++ b/tests/snapshots/oauth_client_metadata__discovery_failure_blocks_metadata.snap @@ -30,6 +30,7 @@ Target: https://client.example.com/metadata.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -39,4 +40,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 25 skipped. Exit code: 2 +Summary: 1 passed, 0 failed (spec), 1 network errors, 0 advisories, 26 skipped. Exit code: 2 diff --git a/tests/snapshots/oauth_client_metadata__dpop_bound_false.snap b/tests/snapshots/oauth_client_metadata__dpop_bound_false.snap index 84b8c58..549cc8f 100644 --- a/tests/snapshots/oauth_client_metadata__dpop_bound_false.snap +++ b/tests/snapshots/oauth_client_metadata__dpop_bound_false.snap @@ -29,6 +29,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__loopback_skips_all_metadata_checks.snap b/tests/snapshots/oauth_client_metadata__loopback_skips_all_metadata_checks.snap index 225d7a1..5a7d1f6 100644 --- a/tests/snapshots/oauth_client_metadata__loopback_skips_all_metadata_checks.snap +++ b/tests/snapshots/oauth_client_metadata__loopback_skips_all_metadata_checks.snap @@ -27,6 +27,7 @@ Target: http://localhost/ [SKIP] `scope` field is present — metadata is implicit for loopback clients [SKIP] `scope` includes the `atproto` token — metadata is implicit for loopback clients [SKIP] `scope` parses against the atproto permission grammar — metadata is implicit for loopback clients +[SKIP] `client_uri` hostname matches `client_id` — metadata is implicit for loopback clients == JWKS == [SKIP] JWKS is present — jwks not applicable to loopback clients [SKIP] JWKS URI is fetchable — jwks not applicable to loopback clients @@ -36,4 +37,4 @@ Target: http://localhost/ [SKIP] Keys use signing use — jwks not applicable to loopback clients [SKIP] Algorithms are modern EC — jwks not applicable to loopback clients -Summary: 1 passed, 0 failed (spec), 0 network errors, 0 advisories, 26 skipped. Exit code: 0 +Summary: 1 passed, 0 failed (spec), 0 network errors, 0 advisories, 27 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_metadata__metadata_non_200_2xx_is_spec_violation.snap b/tests/snapshots/oauth_client_metadata__metadata_non_200_2xx_is_spec_violation.snap index a9b9350..5fce991 100644 --- a/tests/snapshots/oauth_client_metadata__metadata_non_200_2xx_is_spec_violation.snap +++ b/tests/snapshots/oauth_client_metadata__metadata_non_200_2xx_is_spec_violation.snap @@ -31,6 +31,7 @@ Target: https://client.example.com/metadata.json [SKIP] `scope` field is present — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` includes the `atproto` token — blocked by oauth_client::discovery::metadata_document_fetchable [SKIP] `scope` parses against the atproto permission grammar — blocked by oauth_client::discovery::metadata_document_fetchable +[SKIP] `client_uri` hostname matches `client_id` — blocked by oauth_client::discovery::metadata_document_fetchable == JWKS == [SKIP] JWKS is present — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] JWKS URI is fetchable — blocked by oauth_client::metadata::raw_document_deserializes @@ -40,4 +41,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — blocked by oauth_client::metadata::raw_document_deserializes [SKIP] Algorithms are modern EC — blocked by oauth_client::metadata::raw_document_deserializes -Summary: 1 passed, 1 failed (spec), 0 network errors, 0 advisories, 25 skipped. Exit code: 1 +Summary: 1 passed, 1 failed (spec), 0 network errors, 0 advisories, 26 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__metadata_non_json_content_type_is_spec_violation.snap b/tests/snapshots/oauth_client_metadata__metadata_non_json_content_type_is_spec_violation.snap index a87ff83..fcf63d9 100644 --- a/tests/snapshots/oauth_client_metadata__metadata_non_json_content_type_is_spec_violation.snap +++ b/tests/snapshots/oauth_client_metadata__metadata_non_json_content_type_is_spec_violation.snap @@ -30,6 +30,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -39,4 +40,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 24 passed, 1 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__native_happy.snap b/tests/snapshots/oauth_client_metadata__native_happy.snap index a6221e0..07e2e89 100644 --- a/tests/snapshots/oauth_client_metadata__native_happy.snap +++ b/tests/snapshots/oauth_client_metadata__native_happy.snap @@ -26,6 +26,7 @@ Target: https://app.example.com/oauth-client-metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — jwks not required for native clients [SKIP] JWKS URI is fetchable — jwks not required for native clients @@ -35,4 +36,4 @@ Target: https://app.example.com/oauth-client-metadata.json [SKIP] Keys use signing use — jwks not required for native clients [SKIP] Algorithms are modern EC — jwks not required for native clients -Summary: 18 passed, 0 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 0 +Summary: 18 passed, 0 failed (spec), 0 network errors, 0 advisories, 9 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_metadata__native_redirect_scheme_mismatch.snap b/tests/snapshots/oauth_client_metadata__native_redirect_scheme_mismatch.snap index 4c4491a..920baf8 100644 --- a/tests/snapshots/oauth_client_metadata__native_redirect_scheme_mismatch.snap +++ b/tests/snapshots/oauth_client_metadata__native_redirect_scheme_mismatch.snap @@ -29,6 +29,7 @@ Target: https://app.example.com/oauth-client-metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — jwks not required for native clients [SKIP] JWKS URI is fetchable — jwks not required for native clients @@ -38,4 +39,4 @@ Target: https://app.example.com/oauth-client-metadata.json [SKIP] Keys use signing use — jwks not required for native clients [SKIP] Algorithms are modern EC — jwks not required for native clients -Summary: 17 passed, 1 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 1 +Summary: 17 passed, 1 failed (spec), 0 network errors, 0 advisories, 9 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__public_happy.snap b/tests/snapshots/oauth_client_metadata__public_happy.snap index b4b33df..86efa9a 100644 --- a/tests/snapshots/oauth_client_metadata__public_happy.snap +++ b/tests/snapshots/oauth_client_metadata__public_happy.snap @@ -26,6 +26,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — jwks not required for public clients [SKIP] JWKS URI is fetchable — jwks not required for public clients @@ -35,4 +36,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — jwks not required for public clients [SKIP] Algorithms are modern EC — jwks not required for public clients -Summary: 18 passed, 0 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 0 +Summary: 18 passed, 0 failed (spec), 0 network errors, 0 advisories, 9 skipped. Exit code: 0 diff --git a/tests/snapshots/oauth_client_metadata__public_with_token_endpoint_auth.snap b/tests/snapshots/oauth_client_metadata__public_with_token_endpoint_auth.snap index 73be6bd..de6be45 100644 --- a/tests/snapshots/oauth_client_metadata__public_with_token_endpoint_auth.snap +++ b/tests/snapshots/oauth_client_metadata__public_with_token_endpoint_auth.snap @@ -29,6 +29,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [SKIP] JWKS is present — jwks not required for public clients [SKIP] JWKS URI is fetchable — jwks not required for public clients @@ -38,4 +39,4 @@ Target: https://client.example.com/metadata.json [SKIP] Keys use signing use — jwks not required for public clients [SKIP] Algorithms are modern EC — jwks not required for public clients -Summary: 17 passed, 1 failed (spec), 0 network errors, 0 advisories, 8 skipped. Exit code: 1 +Summary: 17 passed, 1 failed (spec), 0 network errors, 0 advisories, 9 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__scope_grammar_invalid.snap b/tests/snapshots/oauth_client_metadata__scope_grammar_invalid.snap index 068af9e..5f9866e 100644 --- a/tests/snapshots/oauth_client_metadata__scope_grammar_invalid.snap +++ b/tests/snapshots/oauth_client_metadata__scope_grammar_invalid.snap @@ -36,6 +36,7 @@ Target: https://client.example.com/metadata.json · ╰── invalid token 28 │ "token_endpoint_auth_method": "private_key_jwt", ╰──── +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -45,4 +46,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 23 passed, 1 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1 +Summary: 23 passed, 1 failed (spec), 0 network errors, 0 advisories, 3 skipped. Exit code: 1 diff --git a/tests/snapshots/oauth_client_metadata__signing_alg_none_is_spec_violation.snap b/tests/snapshots/oauth_client_metadata__signing_alg_none_is_spec_violation.snap index e1c88fb..ec740ad 100644 --- a/tests/snapshots/oauth_client_metadata__signing_alg_none_is_spec_violation.snap +++ b/tests/snapshots/oauth_client_metadata__signing_alg_none_is_spec_violation.snap @@ -29,6 +29,7 @@ Target: https://client.example.com/metadata.json [OK] `scope` field is present [OK] `scope` includes the `atproto` token [OK] `scope` parses against the atproto permission grammar +[SKIP] `client_uri` hostname matches `client_id` — `client_uri` not declared == JWKS == [OK] JWKS is present [SKIP] JWKS URI is fetchable — jwks is inline @@ -41,4 +42,4 @@ Target: https://client.example.com/metadata.json [OK] Keys use signing use [OK] Algorithms are modern EC -Summary: 23 passed, 2 failed (spec), 0 network errors, 0 advisories, 1 skipped. Exit code: 1 +Summary: 23 passed, 2 failed (spec), 0 network errors, 0 advisories, 2 skipped. Exit code: 1