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
16 changes: 8 additions & 8 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
* @alex-au-922
* @alex-au-922 @DebugTsang @sammyfung

/.github/ @alex-au-922
/.goreleaser.yaml @alex-au-922
/cmd/ @alex-au-922
/internal/ @alex-au-922
/scripts/release/ @alex-au-922
/go.mod @alex-au-922
/go.sum @alex-au-922
/.github/ @alex-au-922 @DebugTsang @sammyfung
/.goreleaser.yaml @alex-au-922 @DebugTsang @sammyfung
/cmd/ @alex-au-922 @DebugTsang @sammyfung
/internal/ @alex-au-922 @DebugTsang @sammyfung
/scripts/release/ @alex-au-922 @DebugTsang @sammyfung
/go.mod @alex-au-922 @DebugTsang @sammyfung
/go.sum @alex-au-922 @DebugTsang @sammyfung
9 changes: 8 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ jobs:
id: tools
run: scripts/release/load-tool-versions.sh

- name: Install pinned ShellCheck
run: >-
scripts/release/install-shellcheck.sh
"$RUNNER_TEMP/eventctl-shellcheck-bin"

- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
Expand Down Expand Up @@ -75,7 +80,9 @@ jobs:
run: go run golang.org/x/vuln/cmd/govulncheck@${{ steps.tools.outputs.govulncheck }} ./...

- name: ShellCheck
run: find scripts -type f -name '*.sh' -print0 | xargs -0 shellcheck
run: >-
find scripts -type f -name '*.sh' -print0 |
xargs -0 "$RUNNER_TEMP/eventctl-shellcheck-bin/shellcheck"

- name: Check Bash formatting
run: go run mvdan.cc/sh/v3/cmd/shfmt@${{ steps.tools.outputs.shfmt }} -d -ci scripts
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,11 @@ jobs:
id: tools
run: scripts/release/load-tool-versions.sh

- name: Install pinned ShellCheck
run: >-
scripts/release/install-shellcheck.sh
"$RUNNER_TEMP/eventctl-shellcheck-bin"

- name: Set up Go
uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
Expand All @@ -74,7 +79,8 @@ jobs:

- name: Run complete Bash and workflow gates
run: |
find scripts -type f -name '*.sh' -print0 | xargs -0 shellcheck
find scripts -type f -name '*.sh' -print0 | \
xargs -0 "$RUNNER_TEMP/eventctl-shellcheck-bin/shellcheck"
go run mvdan.cc/sh/v3/cmd/shfmt@${{ steps.tools.outputs.shfmt }} -d -ci scripts
go run github.com/rhysd/actionlint/cmd/actionlint@${{ steps.tools.outputs.actionlint }}
scripts/release/check-action-pins.sh
Expand Down Expand Up @@ -268,6 +274,7 @@ jobs:
runs-on: ubuntu-24.04
timeout-minutes: 10
permissions:
attestations: read
contents: read
steps:
- name: Check out verification scripts
Expand Down Expand Up @@ -322,6 +329,7 @@ jobs:
runs-on: ${{ matrix.runner }}
timeout-minutes: 15
permissions:
attestations: read
contents: read
steps:
- name: Check out verification scripts
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ eventctl key generate|show|backup
eventctl recipient generate|show
eventctl identity register|verify
eventctl team propose|consent|verify
eventctl submission pack|inspect|verify|prepare|verify-request|decrypt-verify
eventctl submission pack|inspect|verify|prepare|authenticate-request|verify-request|decrypt-verify
eventctl replay classify
eventctl receipt sign|verify
eventctl scorer validate-request|sign-result|verify
Expand All @@ -59,6 +59,13 @@ config verification requires the signed organizer-root delegation and every
explicit root public key. Run a command with missing arguments to receive its
exact usage contract as structured JSON.

`submission authenticate-request` verifies the signed request, actor,
registered key, repository, event/config, validity-window, digest, and replay
bindings without reading mutable pull-request metadata or the referenced
bundle. It is a replay-lookup primitive, not submission admission: a request
that is not already present in protected replay state must still pass
`submission verify-request` against fresh PR metadata and the exact bundle.

`eventctl help`, `eventctl --help`, and `eventctl -h` return successful
machine-readable help in the same `pythonhk.eventctl/output/v1` response wrapper
as ordinary commands. Command-family and exact-command help are available as,
Expand Down
1 change: 1 addition & 0 deletions cmd/eventctl/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ var helpGroups = map[string]helpGroup{
{"inspect", "Inspect the public framing metadata of an encrypted bundle.", "eventctl submission inspect --bundle PATH --out PATH"},
{"verify", "Verify a bundle and its signed pack record without decrypting it.", "eventctl submission verify --config PATH --authority PATH --state-meta PATH --registry PATH --bundle submission.eventctl --record PATH --out PATH"},
{"prepare", "Create a signed submission request for an existing bundle.", "eventctl submission prepare --config PATH --authority PATH --state-meta PATH --registry PATH --key PATH --actor-id ID --metadata PATH --bundle submission.eventctl --record PATH --out PATH [--passphrase-file PATH|-]"},
{"authenticate-request", "Authenticate immutable request bindings without fresh PR or bundle access.", "eventctl submission authenticate-request --config PATH --authority PATH --state-meta PATH --registry PATH --request PATH --expect-actor-id ID --source-time RFC3339 --out PATH"},
{"verify-request", "Verify a submission request at its trusted source time.", "eventctl submission verify-request --config PATH --authority PATH --state-meta PATH --registry PATH --request PATH --metadata PATH --bundle PATH --expect-actor-id ID --source-time RFC3339 --out PATH"},
{"decrypt-verify", "Verify acceptance, decrypt, and safely extract a submission.", "eventctl submission decrypt-verify --config ARCHIVED_PATH --authority PATH --state-meta PATH --registry PATH --request PATH --acceptance RECEIPT --bundle PATH --identity PATH [--identity PATH ...] --out-dir PRIVATE_DIR --out PATH [--record PATH] [--passphrase-file PATH|-] [--expect-actor-id ID] [--expect-attempt-id UUID]"},
},
Expand Down
8 changes: 5 additions & 3 deletions cmd/eventctl/identity.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,11 +64,12 @@ func identityRegister(args []string, stderr io.Writer) (any, error) {
return nil, verificationError("decrypt participant key", err)
}
issued := time.Now().UTC().Truncate(time.Second)
raw, err := envelope.NewRegistration(envelope.RegistrationParams{EventID: event.EventID, EventEpoch: event.EventEpoch, OperationID: *requestID, ActorID: *actorID, KeyEpoch: *keyEpoch, BaseRepository: event.BaseRepository, ConfigDigest: digest, TermsDigest: event.Registration.TermsDigest, IssuedAt: issued, ExpiresAt: issued.Add(time.Duration(event.Registration.RequestTTLSeconds) * time.Second)}, pair.Private)
requestTTL := time.Duration(event.Registration.RequestTTLSeconds) * time.Second
raw, err := envelope.NewRegistration(envelope.RegistrationParams{EventID: event.EventID, EventEpoch: event.EventEpoch, OperationID: *requestID, ActorID: *actorID, KeyEpoch: *keyEpoch, BaseRepository: event.BaseRepository, ConfigDigest: digest, TermsDigest: event.Registration.TermsDigest, IssuedAt: issued, ExpiresAt: issued.Add(requestTTL)}, pair.Private)
if err != nil {
return nil, invalidError("create registration", err)
}
verified, err := envelope.VerifyRegistration(raw, envelope.Expected{EventID: event.EventID, EventEpoch: event.EventEpoch, RepositoryID: event.BaseRepository.ID, ActorID: *actorID, ConfigDigest: digest, Now: issued})
verified, err := envelope.VerifyRegistration(raw, envelope.Expected{EventID: event.EventID, EventEpoch: event.EventEpoch, RepositoryID: event.BaseRepository.ID, ActorID: *actorID, ConfigDigest: digest, Now: issued}, requestTTL)
if err != nil {
return nil, verificationError("self-verify registration", err)
}
Expand Down Expand Up @@ -109,7 +110,8 @@ func identityVerify(args []string) (any, error) {
if err != nil {
return nil, ioError("read registration request", err)
}
verified, err := envelope.VerifyRegistration(raw, envelope.Expected{EventID: event.EventID, EventEpoch: event.EventEpoch, RepositoryID: event.BaseRepository.ID, ActorID: *actorID, ConfigDigest: digest, Now: sourceTime})
requestTTL := time.Duration(event.Registration.RequestTTLSeconds) * time.Second
verified, err := envelope.VerifyRegistration(raw, envelope.Expected{EventID: event.EventID, EventEpoch: event.EventEpoch, RepositoryID: event.BaseRepository.ID, ActorID: *actorID, ConfigDigest: digest, Now: sourceTime}, requestTTL)
if err != nil {
return nil, verificationError("verify registration", err)
}
Expand Down
2 changes: 1 addition & 1 deletion cmd/eventctl/scorer.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ func loadScorerTrust(configPath, authorityPath, statePath, acceptancePath string

func verifyScorerAcceptance(verified receipt.Verified, request scorer.Request) error {
document := verified.Document
if verified.DocumentDigest != request.ReservationReceiptDigest || document.RequestKind != envelope.SubmissionKind || document.Outcome != "accepted" || !document.QuotaCharged || document.ActorID != request.ActorID || document.TeamID == nil || *document.TeamID != request.TeamID || document.AttemptID == nil || *document.AttemptID != request.AttemptID || document.RequestDocumentDigest != request.SubmissionEnvelopeDigest || !document.StateAfter.Equal(request.Reservation) || document.SourceCreatedAt != request.SourceCreatedAt || document.IssuedAt != request.AcceptedAt || document.ScorerResultDigest != nil || document.ReservationReceiptDigest != nil {
if verified.DocumentDigest != request.ReservationReceiptDigest || document.RequestKind != envelope.SubmissionKind || document.Outcome != "accepted" || !document.QuotaCharged || document.ActorID != request.ActorID || document.TeamID == nil || *document.TeamID != request.TeamID || document.AttemptID == nil || *document.AttemptID != request.AttemptID || document.RequestDocumentDigest == nil || *document.RequestDocumentDigest != request.SubmissionEnvelopeDigest || !document.StateAfter.Equal(request.Reservation) || document.SourceCreatedAt != request.SourceCreatedAt || document.IssuedAt != request.AcceptedAt || document.ScorerResultDigest != nil || document.ReservationReceiptDigest != nil {
return errors.New("reservation receipt does not exactly bind scorer request acceptance")
}
if err := document.ValidateSourceWindow(request.IssuedAt, request.ExpiresAt); err != nil {
Expand Down
Loading