Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
88 changes: 88 additions & 0 deletions docs/verification/encrypted-action-results/evidence.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
# Encrypted Action Results Evidence

Revision: working tree.

## Current-stage criteria

- C1: verified to stated coverage by generation, Buf lint, Buf breaking, and
`TestActionInvokeTaskThreadsEncryptionConfigs`.
- C2: verified to stated coverage by the existing action and connectorbuilder
suites plus secret-registration rejection tests.
- C3: verified to stated coverage for missing, nil, and unknown-provider
recipients; each case asserts the handler was not invoked.
- C4: verified to stated coverage for public secret fields, undeclared and
non-secret names, duplicate names, nil values, empty names, empty bytes, handler
errors, and injected encryption failure.
- C5: verified to stated coverage for two plaintext values with two age recipients,
including name, description, schema, decrypted bytes, and the full P × R fan-out.
- C6: verified to stated coverage by inline and pending-then-status cases. The
status test also mutates the caller-owned recipient after invoke and proves
settlement uses the captured recipient.
- C7: verified to stated coverage by focused race tests and secret-handler
cancellation followed by late encrypted completion. This is measured execution,
not exhaustive schedule coverage.
- C8: verified to stated coverage by assertions that public responses and RPC
messages omit plaintext, including handler-error, encryption-error, and panic
paths. Recovered panic values are not logged or returned. Connector-supplied
ordinary error strings remain outside this guarantee.
- C9: verified by inspection. Existing handlers add constant adapter work and no
encryption. Secret handlers perform O(P × R) encryption and retain O(P × R)
ciphertext.

## Implementation-obligation addendum

- Registration stores an immutable set of secret return names derived from the
schema. `Register` rejects schemas with secret return types; only
`RegisterWithSecrets` can install their handlers.
- `InvokeActionWithWaitAndEncryption` clones and validates every recipient before
creating an `OutstandingAction` or invoking the handler. The clone prevents
caller mutation from changing recipients while detached work runs.
- The detached handler holds plaintext only in its local `actionHandlerResult`.
`prepareActionResult` validates names and public-field exclusion, encrypts the
values, and passes only ciphertext to `setOutcomeWithEncryptedData`.
- The `OutstandingAction` mutex owns status, public response, encrypted data,
annotations, errors, and provisional-cancellation replacement. Invoke and status
read all five result components under that mutex.
- `setOutcomeWithEncryptedData` clones the public response, ciphertext messages,
and annotations before publication. Error, panic, and encryption-failure paths
retain no encrypted or plaintext result.
- `ActionManager.encryptPlaintext` is initialized to
`EncryptionManager.Encrypt`; the package test replaces it before invocation to
prove an encryption failure settles as FAILED without publishing plaintext.
- Existing `InvokeAction`, `InvokeActionWithWait`, `GetActionStatus`, and
`ActionHandler` signatures remain. Their adapters use the same registration,
lifecycle, and settlement functions as secret handlers.
- The exported `connectorbuilder.ActionManager` method set remains unchanged.
Connector dispatch asserts a private encrypted-result extension implemented by
the SDK manager.
- Global and resource registries install the same `registeredActionHandler` and
converge in `invokeRegisteredAction`.
- Local invocation has additive constructors/options that carry recipients into
`ActionInvokeTask`; existing constructors delegate with no recipients.

## Commands

- `make protofmt && make protogen`: passed.
- `buf lint`: passed.
- `buf breaking --against '.git#branch=main'`: passed.
- `go test -count=1 ./pkg/actions ./pkg/connectorbuilder ./pkg/tasks/c1api ./pkg/tasks/local`:
passed as focused package runs; the c1api assertion was run as
`TestActionInvokeTaskThreadsEncryptionConfigs`.
- `go test -race -count=1 ./pkg/actions ./pkg/connectorbuilder`: passed.
- `golangci-lint run --timeout=3m ./pkg/actions/... ./pkg/connectorbuilder/...
./pkg/connectorrunner/... ./pkg/tasks/local/...`: passed with zero issues.
- `make lint`: the implementation's `nilerr` finding was fixed. The repository-wide
run remains red on six pre-existing findings in `pkg/dotc1z`, `pkg/crypto`,
`pkg/sync`, and the deprecated action-status name assignment.
- `go test -tags=baton_lambda_support ./...`: all affected packages passed. The
repository-wide run remains red because
`pkg/tasks/c1api.TestBootstrapSucceedsOnFirstAttempt` timed out and two
`pkg/uhttp` tests could not write their SQLite database in this environment.

## Final audit

The post-CO-001 independent implementation read found no remaining HIGH or MEDIUM
defects. Its LOW gaps were reduced by adding the compile-time
`encryptedActionManager` assertion and a ciphertext ownership-clone test. Panic-log
redaction remains verified by direct code inspection plus an RPC payload test, not
by a captured-log oracle.
99 changes: 99 additions & 0 deletions docs/verification/encrypted-action-results/plan.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Encrypted Action Results Verification Plan

Status: frozen implementation-blind baseline.

## Risk

This change is HIGH risk. A plaintext action result can cross an RPC boundary,
enter task storage, and be logged. Remediation cannot retract a disclosed secret,
and the public protobuf and Go APIs have consumers outside this repository.

The feature is opt-in. Existing `ActionHandler` registrations and actions without
secret return values retain their current behavior.

## Contract

- C1 supplies encryption recipients on `ActionInvokeTask`; the task handler copies
them to `InvokeActionRequest`.
- A new handler type returns public result fields separately from
`PlaintextData`.
- A secret handler cannot run unless at least one valid encryption recipient was
supplied.
- Every plaintext result name identifies exactly one `return_types` field marked
`is_secret`; duplicate, empty, undeclared, and non-secret names are rejected.
- A public result struct must not contain a field declared secret.
- Encryption runs once when the handler settles. `OutstandingAction` retains only
ciphertext, never plaintext.
- A completed inline response and every later status response return the same
encrypted values. Pending and running responses contain no encrypted values.
- One plaintext value and N recipients produce N `EncryptedData` values. Encryption
failure settles the action as failed without exposing plaintext.
- Existing handlers, deprecated action managers, and actions with only public
return fields require no encryption configuration and preserve their API behavior.
- `EncryptedData.name` equals the matching return field name.

## Coverage model

The executable dimensions are:

- handler: existing / secret;
- scope: global / resource;
- observation: completed inline / pending then status;
- recipients: missing / invalid / one / multiple;
- output: no plaintext / one plaintext / duplicate names / empty name or bytes /
undeclared name / name declared non-secret / secret name also present publicly;
- handler result: success / error / panic / cancellation.

Global and resource registration share the same result adapter and settlement
function; representative tests may reduce output-validation and encryption-failure
cells across scope after implementation inspection confirms that path.

## Criteria

- C1: Generated protobufs expose encryption configs on action invocation tasks and
requests, and encrypted data on invoke and status responses.
- C2: Existing handler behavior and source compatibility remain intact.
- C3: Secret handlers reject missing or invalid recipients before provider work.
- C4: Secret output validation rejects every invalid output class without returning
plaintext.
- C5: Encryption fan-out preserves metadata and creates one ciphertext per
plaintext-recipient pair.
- C6: Inline completion and status polling expose identical ciphertext.
- C7: Concurrent status reads cannot race with settlement or observe a partial
outcome.
- C8: Logs and RPC messages contain no plaintext result.
- C9: Existing actions incur no asymptotic cost change; secret actions add
O(P × R) encryption work for P plaintext values and R recipients.

## Instruments

- Proto generation and Buf lint/breaking checks cover C1.
- Table-driven package tests cover C2-C6 and the output-validation rows.
- Race detection on `pkg/actions` and `pkg/connectorbuilder` covers C7.
- Tests assert plaintext absence from public structs and protobuf responses for C8.
- Code inspection confirms the cost expression and that existing handlers bypass
encryption work for C9.

Evidence and criterion status are recorded in `evidence.md`.

## Change orders

### CO-001 — compatibility and local invocation

Source: independent implementation audits.

Classification:

- Correction: keep the exported `connectorbuilder.ActionManager` method set
unchanged. Encrypted dispatch is an internal optional interface implemented by
the SDK action manager.
- Correction: redact recovered panic values from logs and action errors because a
connector can panic with secret-bearing data.
- Extension: add local action-invocation constructors and runner options that
accept encryption recipients and retain the existing constructors as nil-recipient
delegates.

Affected criteria: C2, C7, C8. Verification adds compilation of existing action
consumers, a panic-redaction test, local task recipient plumbing, and another focused
race run. The extension does not change the protobuf contract or secret settlement
path.
12 changes: 10 additions & 2 deletions pb/c1/config/v1/config.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 5 additions & 1 deletion pb/c1/config/v1/config_protoopaque.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading