Repository navigation
Declare typed secret action outputs before producer execution #1192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2a3bd64
528830d
9a55025
a680c62
da275f1
4483426
899cb2f
b4c6a5b
c65a6c4
490593b
76d6561
b008f89
a93ec56
864fc90
32121b0
020da74
24b852f
21fe49f
1a072f7
5bae0e6
5980f24
69b9808
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,19 @@ | ||
| # Evidence ledger | ||
|
|
||
| Base: released v0.42.3, commit 2e045d482d592a9462b5f87c70a6113fe87ec54a. Source declaration/guard: 528830db; generated protobuf: 9a550250; immutable advertised schema correction: 4483426d. No release is claimed. | ||
|
|
||
| | Criterion | Executable artifact and assertion | Status | | ||
| | --- | --- | --- | | ||
| | Declaration presence and schema round-trip | TestSecretContentTypeSchemaRoundTrip, binary/JSON equality and HasSecretContentType absent/present; explicit empty ValidateAll refusal | Verified to stated coverage | | ||
| | Illegal declarations | TestSecretContentTypeRegistrationRejectsInvalidDeclarations, global/resource and ordinary/encrypted registration; no published action on invalid input/public/empty/grammar/length | Verified to stated coverage | | ||
| | Pre-handler downgrade prevention | TestTypedSecretOutputRefusesUnacknowledgedCallerBeforeHandler, global/resource; missing/opaque/generic/wrong type/purpose/version/ambiguous/invalid JSON plus unsupported recipients/cardinality; empty action ID, handler counter zero, no allocation | Verified to stated coverage | | ||
| | Exact structured bytes and immutable registration type | TestTypedSecretOutputEncryptsExactHelperBytesWithFrozenDeclaration, actual manager/helper/JWE; mutate original schema after registration; independently open X-Wing HPKE bytes and compare canonical username/password JSON | Verified to stated coverage | | ||
| | Legacy generic compatibility | TestGenericSecretOutputKeepsOpaqueContexts plus existing ActionHandlerWithSecrets tests; absent/explicit generic and old age multi-output/recipient paths | Verified to stated coverage | | ||
| | Instrument adequacy | Removed new guard temporarily, ran account/generic regression: failed because expected error was nil; restored source byte-for-byte | Verified bounded mutation | | ||
| | Source generation | make protofmt; make protogen exit0. Only config.pb.go, config.pb.validate.go, config_protoopaque.pb.go changed; generated separately | Verified | | ||
| | Full package and race | go test -race -v ./pkg/actions -count=1; all named package tests ran/pass, no skips; 11.238s final package execution | Verified to stated coverage | | ||
| | Cross-repository integration | C1 consumer adoption, real member/Store/reveal/canonical codec/renderer | Deferred to consumer integration stage; not an SDK-only claim | | ||
|
|
||
| Initial actual invocation test failed on JWE+Paper due to the pre-existing singleton-JWE validator. That failed assumption is preserved in the change-order history; tests now assert the released contract rather than expanding native/shared validation. The caller context guard establishes agreement, not server authentication or payload admission. No provider operations were executed. | ||
|
|
||
| Snapshot correction: TestSecretOutputAdvertisedSchemaIsAnImmutableSnapshot failed in all six global/resource × absent/generic/password_v2 cases before the fix. The final full race run passes original-pointer, listing-copy and getter-copy mutation controls while actual invocation agrees with the unchanged advertised declaration. Proto inputs/generated files are unchanged by this correction; no regeneration was run. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| # Field metadata transition | ||
|
|
||
| `config.Field.content_type` is MIME metadata. Logical delivery types use one | ||
| `multipass-type-` tag, for example `multipass-type-api_key_v2`. Other tags do | ||
| not select a type. The earlier prototype used Field 8 for a bare logical type; | ||
| that encoding is incompatible and valid bare values are rejected. JSON using | ||
| `secret_content_type` on a Field is also rejected by the legacy transport. | ||
| Native `request_schema` and descriptor `secret_content_type` remain readable; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🟡 Suggestion: This says native |
||
| when new and legacy declarations coexist they must agree. An absent return | ||
| field preserves the legacy issuance contract. A declared native return is one | ||
| named required secret string whose name must match the plaintext result. | ||
|
|
||
| Request values remain nonsecret. Hosts apply defaults before approval; SDK | ||
| validation does not apply defaults. Payload bytes are opaque and are not | ||
| validated against MIME or logical type metadata. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| # Connector-declared secret action output types | ||
|
|
||
| ## Frozen behavior | ||
|
|
||
| A connector declares the content type of each secret action output before its handler runs. The connector owns the value bytes and codec. The caller chooses the destination and acknowledges the declared content type before producer side effects. One secret output can contain a document with multiple fields. | ||
|
|
||
| An absent declaration preserves existing generic output behavior. A present empty declaration, declarations on inputs or public outputs, and malformed identifiers are invalid. Existing arbitrary encryption context behavior remains compatible for undeclared/generic outputs. Explicit structured outputs require a matching typed destination acknowledgement before action allocation and handler execution; an older caller that supplies generic context cannot silently reinterpret a structured output. | ||
|
|
||
| The action schema at registration and invocation is an immutable snapshot. Later caller mutations of schema pointers or encryption configurations cannot change an invocation's declaration or authenticated context. | ||
|
|
||
| Secret bytes remain separate from public return fields and are encrypted without conversion. This change introduces no credential issuance protocol, typed input support, provider lifecycle, release or activation. | ||
|
|
||
| ## Risk and verification | ||
|
|
||
| HIGH: a mixed-version caller can otherwise silently change durable payload meaning after a producer performs an external effect. Prevention must run before the handler; post-result checking cannot reverse that effect. No grant-scale or artifact-open hot path changes: checks are linear in schema fields and encryption configurations, with a bounded context parse only for explicit typed outputs. | ||
|
|
||
| | Criterion | Required instrument | Initial status | | ||
| | --- | --- | --- | | ||
| | Declaration absent/present round-trip | Descriptor and binary/JSON schema round-trip | Evidence incomplete | | ||
| | Invalid placement/value refused | Global/resource registration tables; assert no schema published | Evidence incomplete | | ||
| | Old generic caller refuses typed output | Invoke actual ActionManager with generic/missing/wrong context; producer-call count zero | Evidence incomplete | | ||
| | Matching typed context reaches producer | Actual manager, real JWE recipient and encrypted structured bytes | Evidence incomplete | | ||
| | Legacy generic compatibility | Existing secret-action tests plus arbitrary-context controls | Evidence incomplete | | ||
| | Immutable declaration/config | Mutate original schema/config after registration/dispatch; verify frozen output | Evidence incomplete | | ||
| | Result boundaries | Public-secret collision, undeclared/duplicate/required result checks | Existing tests; current change evidence incomplete | | ||
| | Generated compatibility | Owning protobuf generation and diff, source committed before generated | Evidence incomplete | | ||
|
|
||
| Instrument adequacy: demonstrate the mixed-version regression fails when its pre-handler acknowledgement check is removed. Review changed branch coverage and preserve explicit gaps. Registration global/resource paths are a required cross-product; ordinary/encrypted handler registration both enforce declaration placement. No test contacts an upstream provider. | ||
|
|
||
| ## Boundary resolution | ||
|
|
||
| Exact additive field and acknowledgement interpretation require architecture disposition before schema or authority changes. Source inspection was explicitly required to establish whether existing APIs suffice; it preceded this plan. Preserve that exception instead of claiming implementation-blind discovery. | ||
|
|
||
| ## Change orders | ||
|
|
||
| Append any contract or enforcement ownership change here before implementation. | ||
|
|
||
| ### Change order 1: resolved declaration and caller acknowledgement | ||
|
|
||
| Architecture disposition selects optional config.Field.secret_content_type=8 and a pre-handler check of existing full-knowledge JWE context purpose/version/type. Check every JWE recipient, reject duplicate JSON keys, and require one secret return for non-generic types. A matching JWE recipient may coexist with Paper/age recipients. Generic declarations retain opaque contexts and existing multi-output transport. The guard establishes type agreement only, not server authentication or payload validity. Tests cover global/resource invocation, invalid placement, mixed recipients and immutable registered type metadata. Full catalog ownership remains with the consumer; SDK checks syntax only. | ||
|
|
||
| ### Change order 2: preserve existing singleton-JWE transport | ||
|
|
||
| Executed invocation evidence showed that released ValidateEncryptionConfigs rejects any JWE recipient in a configuration set with length other than one. The earlier JWE+Paper positive assumption was counterfactual. Architecture correction preserves that existing restriction; JWE+age and multi-JWE are rejection controls before action allocation/handler effects. The positive typed path uses exactly one JWE recipient and one secret output. Generic age-only multi-recipient/multi-output behavior is unchanged. NewEncryptionManager does not itself enforce this configuration validation; the common ActionManager invocation boundary does, before construction and handler dispatch. No shared/native crypto API changes are introduced. | ||
|
|
||
| ### Change order 3: immutable advertised schema | ||
|
|
||
| A source check identified a correction required by the original immutable-registration criterion: the guard copied type strings, but registration and schema getters retained shared mutable schema pointers. The new six-case global/resource regression failed when caller mutation changed the advertised absent/generic/password declaration into api_key_v2 while the registered handler retained its original type. Publication and read APIs now clone schemas. Mutations of the original, listed and fetched schemas cannot alter advertised/enforced agreement. This adds linear copying in action schema size on registration/discovery, outside declared artifact-open/grant-scale hot paths; no provider, store or credential lifecycle changes. |
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🟡 Suggestion: This ledger (and
plan.mdchange order 1) still describesHasSecretContentTypeandconfig.Field.secret_content_type=8, and it cites pre-squash commit hashes. None of those exist in this PR. The current design iscontent_type(8) plus amultipass-type-entry intags(9), resolved bycrypto.ResolveFieldOutput. Please update these references or remove them.