Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
62503ab
docs(agent): refuse invisible format characters in identity metadata
CBenoit Oct 27, 2026
38dd9c3
test(agent-identity): check invisible format characters in metadata
CBenoit Oct 27, 2026
e2131d8
test(agent-identity): tighten invisible format character checks
CBenoit Oct 27, 2026
dd53104
fix(agent): refuse invisible format characters in mock metadata
CBenoit Oct 27, 2026
e73b978
fix(agent): strip invisible format characters from identity metadata
CBenoit Oct 27, 2026
e3f0c7e
fix(dotnet-agent-identity): refuse invisible format characters in met…
CBenoit Oct 27, 2026
8c3075f
test(agent): pin removal order and name unlisted format characters
CBenoit Oct 27, 2026
14d5279
build(dotnet-agent-identity): version 2026.10.28
CBenoit Oct 27, 2026
3e51fb6
test(agent-identity): make the agent metadata check test platform-ind…
CBenoit Oct 27, 2026
466a2b2
test(agent-identity): accept an agent on a host without a machine ID
CBenoit Oct 27, 2026
6f2d4ae
docs(agent): refuse the remaining invisible code points in identity m…
CBenoit Oct 27, 2026
97ffd66
test(agent-identity): check the remaining invisible code points in me…
CBenoit Oct 27, 2026
df47137
fix(agent): refuse the remaining invisible code points in mock metadata
CBenoit Oct 27, 2026
0aca42c
fix(agent): strip the remaining invisible code points from identity m…
CBenoit Oct 27, 2026
2b6ba09
fix(dotnet-agent-identity): refuse the remaining invisible code point…
CBenoit Oct 27, 2026
8edfa0f
build(dotnet-agent-identity): version 2026.10.28.1
CBenoit Oct 27, 2026
eca9377
test(dotnet-agent-identity): refuse every code point of each invisibl…
CBenoit Oct 27, 2026
6fe49c6
docs(agent): state why the mock fixes the invisible list as code points
CBenoit Oct 27, 2026
4c95181
test(agent): name the Mongolian selector gap after its range
CBenoit Oct 27, 2026
281030d
test(agent-identity): tighten the machine ID and invisible code point…
CBenoit Oct 27, 2026
68cd972
fix(agent): send the Linux machine ID as-is
CBenoit Oct 27, 2026
4ba313d
test(agent-identity): skip the machine ID comparison when the host fi…
CBenoit Oct 27, 2026
0e12acf
docs(agent-identity): note the unreadable machine ID gap in coverage
CBenoit Oct 27, 2026
835eb85
docs(agent): mark the untrimmed machine ID as untested
CBenoit Oct 27, 2026
8780bd7
Merge remote-tracking branch 'origin/master' into claude/metadata-gap…
CBenoit Oct 28, 2026
b3d4bd5
Merge remote-tracking branch 'origin/master' into claude/metadata-gap…
CBenoit Oct 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions crates/agent-identity-conformance/COVERAGE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ The `p_*` tests check an authority and the `a_*` tests the agent; the tests name
| §2 `u` read as text: `user@`, empty user name, `@` in path, non-ASCII host | `a_pending_file_deleted_on_permanent_error` |
| §2.1 precedence of `token_url_mismatch` | `p_enroll_csr_url_refusal_precedes_key_lookup_and_token_state` (over the key lookup, a revoked token and an exhausted one), `p_enroll_csr_url_refusal_precedes_token_expiry`; `p_enroll_csr_must_name_token_url` (`invalid_request` for a CSR that also has a bad self-signature) |
| §3 metadata limits | `p_metadata_limits`, `p_channel_hello_invalid_metadata_rejected` |
| §3 invisible format characters | `p_metadata_invisible_format_characters` (each end of every listed range refused in the hostname, and U+202E in an unknown key, at enrollment without consuming a token use; each code point just outside a range and the unlisted `Cf` code points U+0600, U+110BD and U+1D173 accepted and stored as sent), `p_channel_hello_invalid_metadata_rejected` (U+E007F in `Hello`); the harness test `invisible_format_character_lists_match_the_contract` pins both lists |
| §3.1 invisible format characters removed, empty keys `unknown` or omitted | `a_metadata_invisible_format_characters_removed`, through the metadata override, which also checks that the agent keeps the code points beside the list and omits an optional key (`domain`) left empty; the metadata check of every agent test refuses a listed code point in any value the agent sent, which the harness test `agent_metadata_check_refuses_listed_format_characters_only` pins |
| §3 invisible format characters | `p_metadata_invisible_format_characters` (each end of every listed range, U+00AD through U+E0FFF, and U+2065, U+180D, U+FFF8, U+E0002, U+E001F and U+E0080 inside a range, refused in the hostname, and U+202E in an unknown key, at enrollment without consuming a token use; each code point just outside a range and the unlisted `Cf` code points U+0600, U+110BD and U+13430 accepted and stored as sent, in the hostname and two per unknown key), `p_channel_hello_invalid_metadata_rejected` (U+E0FFF, the last listed code point, in `Hello`); the harness test `invisible_format_character_lists_match_the_contract` pins both lists |
| §3.1 invisible format characters removed, empty keys `unknown` or omitted | `a_metadata_invisible_format_characters_removed`, through the metadata override, which uses the range ends and the six code points inside a range as separators and as a value made only of listed code points, and also checks that the agent keeps the code points beside the list and omits an optional key (`domain`) left empty; the metadata check of every agent test refuses a listed code point in any value the agent sent, which the harness test `agent_metadata_check_refuses_listed_format_characters_only` pins |
| §3.1 `machine_id` present only when the OS provides one | the metadata check of every agent test compares `machine_id` with the Linux `/etc/machine-id` after the sanitising of §3.1, and requires the key absent when the file is missing or leaves nothing, and compares nothing when the file cannot be read for another reason; the harness tests `machine_id_is_refused_when_the_host_provides_none`, `machine_id_must_equal_the_host_value`, `machine_id_is_not_compared_when_the_host_value_is_unavailable`, `machine_id_expectation_follows_how_the_host_file_read_ended`, `expected_machine_id_removes_control_characters_and_trims_nothing` and `expected_machine_id_is_truncated_on_a_character_boundary` pin that decision. Windows and macOS values are not compared |
| §4 certificates, §5.1 trust anchors | `p_trust_anchor_lists_roots`, `p_renew_rejects_sha384_csr`, `p_compressed_point_csr_rejected`, `p_csr_bad_self_signature_rejected`, the `csr` vectors; `p_failed_enrollment_consumes_nothing` sends the `bad_self_signature` and `ecdsa_with_sha384` vectors at enrollment, where their enrollment URL (`https://example.test/dvls`) is not the target's `u`, and §2.1 orders `invalid_request` before the `token_url_mismatch` it would draw, so it isolates their rules there |
| §4 chain signature algorithms, CA basicConstraints and keyCertSign | the chain check of `p_trust_anchor_lists_roots`, `p_reset_rebases_root_validity`, `p_renew_happy_path`, `p_renew_within_grace`, `p_rotation_publishes_both_roots_and_issues_from_new`, `p_rotation_grace_renewal_after_early_completion` and `p_rotation_old_root_cert_renewable_after_deadline`, which verifies the root's self-signature too; the harness tests `chain_verifies_p384_intermediate_and_refuses_other_algorithms` and `chain_requires_ca_extensions_on_every_issuer` pin that it accepts a P-384 issuer and refuses another curve and each missing CA extension |
| §4 leaf extensions | the leaf profile check of `p_trust_anchor_lists_roots` (enroll), `p_renew_happy_path` and `p_renew_within_grace` (renew); the harness test `leaf_extensions_outside_the_profile_are_named` pins that the check refuses basicConstraints and names it, and refuses a leaf without the enrollment URL extension, with two, with a critical one, with one holding a `UTF8String` or naming another URL |
Expand Down Expand Up @@ -50,7 +51,8 @@ The `p_*` tests check an authority and the `a_*` tests the agent; the tests name
- Known gaps, with no test yet:
- the §1 conventions beyond the error body, timestamps, repeated members, nesting depth, invalid Unicode and canonical `base64`;
- a renew or check-in body whose metadata holds a control character or an invisible format character (§3), which `p_metadata_limits` and `p_metadata_invisible_format_characters` send only at enrollment and `p_channel_hello_invalid_metadata_rejected` only in `Hello`;
- a code point inside a listed range of §3 other than its ends;
- a code point inside a listed range of §3 other than the six that `p_metadata_invisible_format_characters` and `a_metadata_invisible_format_characters_removed` send;
- the `machine_id` value on Windows and macOS (§3.1), which the metadata check does not compare, because the suite has no independent reading of the SMBIOS UUID or `IOPlatformUUID`, and on a Linux host whose `/etc/machine-id` the suite cannot read for a reason other than its absence;
- the agent's removal of C0, DEL and C1 control characters (§3.1), and its removal of invisible format characters at renew, check-in and `Hello`, because no test sets such a value in the metadata override before those sends;
- an `agent_channel_url` holding an `@`, which the agent treats as absent (§5.2, §7.2), because no mock fault delivers such a URL;
- the shape of the agent's own CSR (§4: one attribute, an `extensionRequest` holding only the enrollment URL extension) and the URL its renewal CSR names, because the mock reports no CSR it received; the mock accepting the agent's enrollments shows only that their CSRs name the token's `u` where the mock reads it;
Expand Down
Loading
Loading