chore(ticket): preserve integrated authentication and WIP test fixes

# Conflicts:
#	crates/workspace-server/src/server_workspace_config_wip_tests.rs
This commit is contained in:
2026-10-09 03:10:39 +09:00
8 changed files with 1000 additions and 261 deletions
@@ -0,0 +1,83 @@
# Runtime request proof rejection diagnostics
`runtime_request_proof_rejected` (`yoi::auth`, WARN) is an internal operational
record. HTTP responses are unchanged: 401 with no proof details (repository
routes retain their existing generic API error envelope). It does **not** establish
why the reported same-machine intermittent 401 occurred. No reproduction or
causal measurement of that incident has been obtained.
## Verification and correlation
- `request_id`: Server-generated UUID identifying this rejection event. It is not
a caller-supplied ID or a response header, and is not a cross-service trace ID.
- `claimed_runtime_id_hash`, `claimed_worker_id_hash`, `claimed_token_id_hash`:
lowercase 64-character hex SHA-256 of
`b"yoi-runtime-proof-diagnostic-id-v1\0" + id.as_bytes()`.
`worker_source::diagnostic_id_hash` exposes this correlation function. Hash a
known Runtime/Worker ID to find its failures; token ID hashes correlate replay
attempts without logging the proof or JTI itself. These are fingerprints, not
encryption: low-entropy IDs can be guessed. Do not place secrets in IDs.
- All claims-derived fields are prefixed `claimed_`, even after signature checks.
`proof_verification` describes check progress, **not an authorized principal**:
- `unverified`: decoding may have succeeded, but signature verification has not.
- `signature_verified`: signature passed; request binding or time failed.
- `request_verified`: signature, request bindings and time passed, but replay,
membership or authority failed.
- When decoding fails, there are no claims fingerprints. Do not infer a Runtime
from a malformed proof. No raw claims, proof, key, header, body or raw error is
logged. The body digest and claim mismatch values are also deliberately absent.
- Method, query-free path, and requested workspace are request metadata, not
authenticated claims. They are bounded to 32, 512 and 128 UTF-8 bytes, with
control characters removed. Truncated paths are not unique identifiers. Query
names and values are never included. Paths are operational metadata, not a
place to put secrets.
## Reasons and their limits
Decoding distinguishes `invalid_format`, `invalid_encoding`, and
`malformed_claims`; no parser error text is included. Signature checks distinguish
`invalid_runtime_public_key` from `invalid_signature` (which cannot tell whether
an attacker, wrong key, corruption, or configuration mismatch caused the failure).
Request binding reports the first mismatch, in the existing check order:
`issuer_mismatch`, `audience_mismatch`, `workspace_mismatch`, `worker_mismatch`,
`permission_mismatch`, `method_mismatch`, `path_mismatch`, `body_digest_mismatch`.
The server selects the trusted key by the unverified issuer and expects that
same issuer/worker; issuer and worker mismatches can be diagnosed by the lower
verifier but are not independently detectable by the current server caller.
These diagnostics do not add new identity checks or change authorization.
`backend_audience_unavailable` denotes missing Backend public URL configuration.
`runtime_trust_missing_or_revoked` deliberately covers both absence and revocation,
as the existing store lookup/filter does not preserve that distinction.
`replay` means JTI consumption returned false. `worker_catalog_membership` means
neither registry membership nor an active create reservation was found.
Store failures identify their check stage without exposing raw errors:
`runtime_trust_authority_unavailable`, `replay_authority_unavailable`,
`worker_catalog_authority_unavailable`, `worker_reservation_authority_unavailable`,
`worker_singleton_authority_denied`. The last can represent either an owner
conflict or an authority failure: the store currently returns a shared error,
so the diagnostic does not guess which. `verification_time_out_of_range` means
that conversion to the JTI consumption timestamp failed; it is not proof expiry.
`invalid` is a fallback for lower verifier errors not classified for this path.
## Time contract and T-728 coordination
This change preserves strict integer-second checks, inclusive bounds, and
verification order: signature, request binding, then `iat > now`, then `exp < now`.
No skew tolerance is added. If both time predicates fail, future issuance wins.
- `issued_in_future`: `time_delta_seconds = iat - now` (positive).
- `expired`: `time_delta_seconds = now - exp` (positive).
- Only these reasons include `issued_at_unix`, `expires_at_unix`,
`verified_at_unix` and `time_tolerance_seconds` (currently zero).
- Deltas use `i64::abs_diff`, preserving the full positive `u64` range without
overflow. All times come from the actual signature-verified rejection and
the exact clock sample used for that decision, not a second log-time sample.
T-728 owns any change to tolerance/validity policy. If it changes these checks,
the error time data, logged effective tolerance, and boundary tests must change
together. Do not label future issuance as expiry or independently recompute the
rejection using a different clock sample. This is instrumentation for the next
incident, not evidence that the original incident has been resolved.
@@ -0,0 +1,33 @@
# T-729: restored base test-only compile blocker
The assigned checkout starts at `f9d4c97f` (WIP 0.2 integration). On 2026-10-08,
`cargo test -p yoi-workspace-server --lib auth_logging_tests` could not compile
because `server_workspace_config_wip_tests.rs` still calls `WipRuntime::discover`
(lines 152 and 192), which no longer exists, and external `WipRuntime::call`
(lines 170 and 200), which is now crate-private. At the initial failure those
files were unchanged by the T-729 diagnostic work.
A narrow test filter still builds all lib test modules, so it cannot isolate the
new authentication boundary tests from this unrelated test API mismatch. This
was escalated on T-729 instead of silently disabling those tests or widening the
Ticket to migrate unrelated configuration tests. Future API migration work should
check affected test-only consumers as well as the normal compilation closure.
The additional no-default-features check also fails in unchanged Runtime modules:
`resource.rs`, `worker_backend.rs` and `worker_source.rs` import feature-gated
`workspace_request`, `reqwest` and `futures` unconditionally. The no-default lib
test build additionally calls feature-gated filesystem constructors. This is not
an auth diagnostic regression and was not repaired by broadening T-729. Default
Runtime crate tests pass (345 library tests, 17 tests in each of the two binaries);
root `cargo check` passes. After correcting the T-729 SHA formatting, the Server
lib test build reports only the four existing WIP API errors above.
## Resolution of the Server prerequisite
Ticket T-729 seq7 explicitly authorized a narrow test-only migration. Commit
`717ff255` replaces the helpers with public Tree, path-centered Inspect and
structured InterfaceReference Invoke. All existing Backend authority, attachment,
mutation, stale observation and unknown-outcome assertions are retained. All 12
`workspace_config_integration` tests pass, and the authentication logging tests
now run (3 passed). No production API was exposed or legacy API revived. The
no-default-features issue remains separate and unresolved.