Repository navigation
Add declarative webhook triggers and versioned CAO subscriptions - #69772
Conversation
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Limit first-class triggers to Projects v2 items and explicitly selected security alert sources, excluding related security webhooks. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep only Projects v2 item and selected security alert subscriptions. Remove general webhook registration and the separate webhook-auth contract, and use standard roles/bots authorization for relayed dispatches. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Complete the macOS NVX test exclusion without disabling portable compiler coverage. The execution fixtures require Linux Bash and GNU utilities. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Require project_id beside types, select alert sources explicitly, and promote severity. Add paired transition declarations while documenting RFC-033 metadata and native payload compatibility gaps. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Keep paired Status transition predicates on the CAO side, match native Projects field-change payloads, and require explicit repository opt-in for synthetic triggers. Mark the new frontmatter experimental and document the remaining gateway integration boundaries. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
@copilot merge main and recompile |
There was a problem hiding this comment.
🔵 Needs a closer look
Unresolved correctness issues and security-sensitive payload transport require final human review.
4 open issues
What changed in this PR
Adds experimental, opt-in webhook triggers to gh-aw, compiling Projects v2 and security events into CAO subscription metadata and workflow-scoped dispatch routes.
Changes:
- Adds trigger validation, paired transition predicates, and repository-level opt-in.
- Validates dispatch envelopes and stages event context for agents, including NVX.
- Adds schemas, documentation, and regression coverage.
| File | Description |
|---|---|
pkg/workflow/workflow_data.go |
Stores webhook subscriptions. |
pkg/workflow/webhook.go |
Parses subscriptions, filters, and routing metadata. |
pkg/workflow/webhook_test.go |
Covers parsing and filter matching. |
pkg/workflow/webhook_status_transitions.go |
Builds paired transition predicates. |
pkg/workflow/webhook_status_transitions_test.go |
Covers transition semantics and validation. |
pkg/workflow/webhook_security_alert_test.go |
Covers security sources and selectors. |
pkg/workflow/webhook_aliases_test.go |
Covers Projects trigger requirements. |
pkg/workflow/unified_prompt_step.go |
Adds conditional webhook instructions. |
pkg/workflow/testdata/webhook-project-item-edited.json |
Supplies a transition payload fixture. |
pkg/workflow/repo_config.go |
Adds CAO opt-in configuration. |
pkg/workflow/nvx_preflight_test.go |
Restricts Linux-dependent execution fixtures. |
pkg/workflow/github_app_requirements.go |
Normalizes selected webhook event names. |
pkg/workflow/github_app_requirements_test.go |
Covers event-name inference. |
pkg/workflow/event_validation.go |
Recognizes the new trigger keys. |
pkg/workflow/data/webhook_events.json |
Defines webhook activities and selectors. |
pkg/workflow/compiler_yaml_runtime_setup.go |
Integrates event staging into agent setup. |
pkg/workflow/compiler_webhook.go |
Generates dispatch routes, validation, and staging. |
pkg/workflow/compiler_webhook_test.go |
Covers generated workflow behavior. |
pkg/workflow/compiler_validators.go |
Emits experimental-feature notices. |
pkg/workflow/compiler_string_api.go |
Integrates webhook handling into string APIs. |
pkg/workflow/compiler_orchestrator_workflow.go |
Integrates trigger lowering into compilation. |
pkg/workflow/compiler_cao_triggers.go |
Enforces repository opt-in. |
pkg/workflow/compiler_cao_triggers_test.go |
Covers opt-in failures and notices. |
pkg/workflow/compiler_activation_context.go |
Adds activation-time envelope validation. |
pkg/parser/schemas/repo_config_schema.json |
Defines CAO configuration syntax. |
pkg/parser/schemas/main_workflow_schema.json |
Defines trigger and selector syntax. |
pkg/parser/schema_webhook_test.go |
Covers accepted and rejected declarations. |
pkg/cli/compile_workflow_processor.go |
Exposes subscription metadata in results. |
pkg/cli/compile_webhook_test.go |
Covers CLI opt-in and JSON contracts. |
pkg/cli/compile_config.go |
Adds subscriptions to validation results. |
docs/src/content/docs/reference/webhook-triggers.mdx |
Documents syntax, transport, and integration limits. |
docs/src/content/docs/reference/triggers.md |
Links the experimental trigger reference. |
actions/setup/js/validate_webhook.test.cjs |
Covers envelope validation and byte limits. |
actions/setup/js/validate_webhook.cjs |
Validates inline dispatch envelopes. |
actions/setup/js/nvx_assets.test.cjs |
Covers event handoff and file protections. |
actions/setup/js/nvx_assets.cjs |
Includes event context in guest state. |
actions/setup/js/check_membership.test.cjs |
Covers rejection of payload identity claims. |
Review effort: Max
…ve-webhook-triggers # Conflicts: # pkg/workflow/compiler_string_api.go Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Merged |
|
@copilot Fix the code for all comments in this review thread. When a review comment includes a suggested change, apply the suggestion exactly. Do not make changes beyond what is described in the linked review thread. |
Co-authored-by: pelikhan <4175913+pelikhan@users.noreply.github.com>
Addressed all four review findings and pushed commit |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Preserve the review fixes and apply the webhook-triggers rename to centralized compilation validation. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ve-webhook-triggers Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Merged the latest
Merged the latest |
|
@copilot address the following outstanding work in one pass:
Push the necessary fixes, reply to each listed review thread and resolve it when addressed. Ignore feedback already answered or resolved. Use the pr-finisher skill and stop when only human review or CI remains; do not trigger CI. Sous-chef head: f6047b0
|
…ve-webhook-triggers # Conflicts: # pkg/workflow/lint/lint.go # pkg/workflow/lint/lint_test.go # pkg/workflow/lint/rule_contract_test.go Co-authored-by: gh-aw-bot <259018956+gh-aw-bot@users.noreply.github.com>
Enable action-owned post-job revocation explicitly for every generated App token, reject gateway cleanup overrides, and support admission-provisioned identity secrets with existing variable fallback. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Merged latest |
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Gate gateway workflows on exact-revision OIDC admission, define the closed continuation profile, and preserve backend-owned discovery timing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Pass the existing metadata frontmatter hash unchanged to the OIDC audience and admission request. Remove runner-side artifact retrieval and rehashing, verify header/literal parity through the real CLI, and retain independent server artifact approval and backend-owned discovery timing. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ve-webhook-triggers Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Adopt the merged threat-detection run output and safe-output binding while preserving compiled gateway provenance, admission, and header-hash guards. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Include the additional main commit that arrived during final verification. Preserve the prior base merge and compiled-header admission correction; validate the new timeout classifier without contacting the live registry. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Replace security-alerts and its sources selector with independent code-scanning-alert and dependabot-alerts declarations. Preserve native subscription events and validate each family's activities, severities, filters, and inferred permissions separately. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>


Summary
Introduce experimental, first-class
on.gateway-dispatchsubscriptions with mandatory CAO GitHub App provenance and hash-bound workflow admission:code-scanning-alertanddependabot-alertstriggers, Jira/Linear/Azure DevOps issues, ten GitHub notification families, and gateway slash/consuming-label command declarations.repository_dispatchrouting; identical discovery throughgh-aw-manifest.webhook_subscriptionsandcompile --json.gateway_provenanceroot job before every built-in, custom, reusable, and prerequisite job.gateway_admissionjob passes the compiler's existing headerfrontmatter_hashunchanged to OIDC and requires an explicit backend decision before any remaining job.actions/create-github-app-tokenwith explicit post-job revocation for compiler-managed runtime tokens and secret-first central identity configuration.Arbitrary/custom webhooks, named secret scanning, Projects classic, and compatibility aliases are unsupported. Native non-gateway behavior is unchanged.
Frontmatter and compilation
Repository opt-in is
{"gateway-dispatch":true}in.github/workflows/aw.json.Code scanning and Dependabot are independent declarations, each emitting exactly one subscription for its own native family (
code_scanning_alertordependabot_alert). Each has separatetypes,severity, andfilters; an empty object selects all activities for that trigger only. Declare both explicitly to receive both. The oldsecurity-alertsbundle andsourcesselector are rejected, including alongside valid triggers. Sharedrepos/orgs, homogeneous envelopes, and read-only source-permission inference remain unchanged.Gateway declarations cannot coexist with native events, schedules, workflow calls/runs, native commands, manual dispatch, explicit repository dispatch, or unknown/future triggers. Multiple nested subscriptions and non-trigger
on.roles/on.botssettings remain allowed. Write-minimum roles remain, but roles/bot allowlists do not authenticate ingress.Schema, raw parsing, preparsed compilation, App-event inference, and the mandatory
gateway-dispatch-literalsrule enforce this boundary, including withstrict: false. Invalid declarations/expressions/provenance overrides emit no lock or manifest. There are no generated native listeners, runner-side command-body checks, implicit manual listeners, or centralized command routers.App provenance and runtime token lifecycle
GH_AW_GATEWAY_APP_IDGH_AW_GATEWAY_APP_BOT_IDGH_AW_GATEWAY_GET_TOKEN_URLGH_AW_GATEWAY_OIDC_AUDIENCEA nonempty secret wins over its matching variable; malformed nonempty secrets fail closed. Environment-only settings cannot reach either control-plane gate. CAO's dispatch private key and bearer token never enter destination secrets, frontmatter, or the manifest.
The read-only compiler-owned root verifies the original event's route, destination repository ID/name, Bot sender, and original
github.actor_id. AuthenticatedGET /apps/{app_slug}andGET /users/{username}bind App ID, slug, bot ID, and login using GitHub-owned API/server/event-path contexts, including Enterprise base paths. Requests are bounded, redirects disabled, and malformed identity/lookup failures reject without credential values. Payload claims and the rerun requester are not dispatch-origin evidence. The gate uses its own read-onlyGITHUB_TOKEN, not App or telemetry minting.Every other job directly requires successful provenance and
verified == 'true'.jobs.gateway_provenancecustomization rejects. Conditions are composed after customization/typed lowering; expression grouping/interpolation checks and exact quoted YAML scalars prevent bypass viaalways(), disjunctions, folded-scalar text, custom activation outputs, orstrict: false. User pre-steps cannot precede verification. After provenance, every remaining job also requires successful hash admission as described below.CAO separately mints an installation token restricted to the approved destination repository and
contents: write, verifies installation/scope/expiry, and dispatches with that exact token without PAT/user/workflow-token fallback. The gate proves the App principal, not a CAO process, tenant, token instance, or provider signature. Receiver and destination revisions must conform together.All three compiler runtime-minting builders emit SHA-pinned
actions/create-github-app-tokenwithskip-token-revoke: false, preserving conditional minting and explicit scopes. A gateway-specific hard check rejects disabled/dynamic/malformed revocation settings in rendered direct action steps across jobs, including imported/customized steps, even with schema validation disabled. Omitted input may use the action's default false. It does not inspect external composite/reusable internals or prove arbitrary shell cleanup. Abrupt runner termination may prevent post hooks; unconditional confirmed revocation is not claimed.Admission-server provisioning is recommended through GitHub's documented Actions-secret public-key, LibSodium encryption, and create/update APIs, restricting organization secrets to approved repositories. Optional runtime credentials belong to a separate approved runtime App through existing
github-appconfiguration. Server-minted dispatch credentials and runtime action-owned tokens have separate cleanup owners.The spec documents JWT → installation lookup → scoped token → dispatch, destination metadata calls, hash-bound admission, local activation validation, and continuation. There is no runtime token-renewal policy or CAO dispatch-token exchange.
Hash-bound admission and backend-owned discovery
Implemented in this branch, including reuse of the existing compiler header hash:
gateway_admissionfollows successful App provenance, with onlycontents: readandid-token: write. Its trusted setup does not mint user-configured App or observability credentials.frontmatter_hashalready emitted ingh-aw-metadataas a trustedGH_AW_GATEWAY_WORKFLOW_HASHstep literal. The client validates and passes it unchanged; it does not fetch repository metadata/workflow contents or compute another digest.core.getIDTokenreceives<approved-base>/gh-aw/gateway/v1/workflow/sha256/<hash>. The masked JWT is presented only to the approved HTTPS endpoint, never to GitHub REST/resource URLs or the agent.200with exactly those fields plus booleanallowed: truepermits continuation; extra credential fields, mismatches, denial, pending refresh, redirects, and failures reject.verified == 'true'outputs. Neither gate uses a job environment, including under--environment.The verifier/discovery/dispatch-table server remains external. It must validate the JWT signature/issuer/claims, source-derived configuration hash, and actual compiled artifact at the signed revision; a caller-selected audience or copied header alone is not content attestation. The existing frontmatter hash is not a full-file/body digest. It must resolve stale metadata before approval, preserve current grants, fence publication against rollback/revocation, and authorize the signed check-run as the expected admission job. Fetching new source does not self-approve it. Discovery may be periodic, event-driven, lazy, or combined: no fixed refresh interval, scan deadline, convergence formula, polling requirement, or cache lifetime is prescribed.
The implemented client/profile and server responsibilities are distinguished in the specification. This is not a deployment, hosted acceptance, or implemented backend verifier/refresh claim.
Prior merged-revision verification: 2,996 JavaScript tests passed across 23 suites, 18 skipped, including 103 admission cases, gateway provenance/resource checks, and the incoming model-startup, cost-guard, repo-memory, and threat-detection changes. Targeted Go compiler/activation/AIC/detection/repo-memory tests and real CLI gateway integration passed, along with JavaScript typecheck/lint, standard Go lint, 345/345 workflow recompilation with no drift, and a 290-page docs build with valid links. The header-hash correction passed the source-change publication gate before merging; regenerated merge output passed the final publication gate. Existing unrelated lint warnings/debt remain outside a clean full-suite claim.
Minimal transport and command semantics
The closed envelope remains numeric schema 2 with
resource-url-types-filters/v2projection. Deliveries contain only a canonical HTTPSurl, selected evidence-backedtypeactivities, and exact matching declared scalarfilters. No native resource/delta objects, unselected text/array values, command arguments, arbitrary state, hydration, or access-denied cached-body fallbacks are forwarded. An invalid element rejects the whole batch; both serialized request and client-payload UTF-8 limits apply before deduplication.Catalogued Projects
body.from/body.toand Azuretags.from/tags.toremain supported only as exact configured scalar literals proven to match. This resolves conflicting prose without permitting unmatched body text or arbitrary transition evidence.${{ toJSON(gateway.events) }}exposes normalized{delivery_id,payload}via environment-variable indirection. Additional resource data requires authenticated workflow clients and trusted endpoints; arbitrary notification URLs/redirects do not receive credentials. Caller/episode lineage and payload redaction remain.Shared
repos/wildcardorgsrestrict independently approved sources and never grant access; provider scopes remain mandatory. Receiving-App inference requests reads except separately authorized label writes and does not expand the workflow'sGITHUB_TOKEN.The notification catalog defines ten families, actions, typed filters, issue/PR discrimination, parent/comment identities, paths, and exact anchors including
#pullrequestreview-N. Enterprise prefixes are checked; review threads require the first delivered canonical comment without hydration. Bodyless transitions/reviews can activate notifications, not slash commands. Commands retain position-zero matching and their narrower catalog.Label declarations require consumption: omitted/true
remove_labelis supported; false rejects. A receiver needs a separately reviewed occurrence-aware source-write protocol, durable admission, confirmed fenced consumption before dispatch, and crash recovery that cannot remove a reapplied label. All three reference receivers reject label-command enrollment rather than attempt an unfenced write. Compiler capability is not receiver readiness.Consolidated implementation findings
?/#delimiters; destination regression fixed.204means acceptance, not execution; cleanup failure never causes redispatch.urlor consistent delivered fallback bound to original Issue/identifier/enrolled workspace. Azure delivered item link or enrolled-base construction from authenticated original item ID; never strip update paths or trust payload origins.The shared spec and both GitHub/provider references are aligned. Each experiment preserves its independent baseline findings and explicit limitations in its own
FINDINGS.mdand README on its closed PR branch.Independent executable backend experiments
All three experimental draft PRs are closed without merging; their nested sessions were archived on request:
449aa70ea687e787181569a4e440e79d75e7fddf539d54e0a836022497fdbc50e2f3da5855b9ae4ef5878c476eba9d0a2e244699fcc81a0879f3a4a2They implemented authentication, protected enrollment, native normalization/catalog matching, minimal projection, durable replay/admission, approved App-token mint/dispatch/revoke, current approval/artifact checks, and uncertainty handling within documented profiles, not production/hosted conformance. They predate the new hash-bound client/profile and do not establish its server-side implementation.
Go uses a single-process POSIX private-file ledger with a retained-record ceiling, strict URL subset, signed-admin Jira profile and explicit fallback-identity ambiguities. Express uses bounded ingress/API/numeric profiles and conservative indistinguishable-content suppression. Python rejects user-owned Projects and uses a delivered-link-only Azure profile plus signed-admin Jira. All reject labels without occurrence fencing. Distributed isolation, trusted onboarding/secret provisioning, automatic quarantine reconciliation, and crash-proof revocation are not implied by local tests. Ingress/admin endpoints, storage, policy files, and digests are not additional shared protocols.
Published contract and verification
Published compiler/spec/runtime revision:
554d6eacef84d5df324d77670be18bfcdd56c79d. Normal pushes preserve existing feature/main history; no force push or rewrite.The separate security-event declarations passed focused parser/compiler/CLI tests, real CLI compilation and manifest assertions with different activities/severities per family, and 316 runtime tests across the batch validator, resource resolver, and context suites. The final source-change publication gate passed standard/custom Go lint, schema freshness, impacted Go tests, and 345/345 workflow no-drift compilation. Documentation built 290 pages with valid internal links. The smoke workflow was regenerated; its existing header
frontmatter_hashand trusted admission-step literal changed together, while its body and native subscription transport stayed unchanged.The seven incoming
origin/maincommits through4840cd8f7a4bb540186a1edaa69f7998882c300fwere merged ind5bfa79e8e, preserving header-hash correction2ec5659384. The merge was conflict-free; compiler regeneration added the incoming detection run-output/binding to the gateway smoke workflow in the published follow-up commit. A further test-only main commit throughff1a14fe97d8384448331f6ffd09b70ab52ad78cwas merged in4c4c4eda2bbefore the security-event split.Pin the normative specification, notification catalog, batch validator, provenance verifier, admission client, and resource resolver. Older receiver conformance does not establish acceptance of this revision.
Historical consolidation at
c6c9855ea34e336d660878be230af428e8e59144: 542 focused tests across six webhook suites, JavaScript formatting/lint/typecheck, and the change-scoped final publication gate passed; no changed Go files, so impacted Go tests correctly skipped. Documentation-only follow-ups passed fast gates. Documentation built 289 pages with valid internal links; the spec's 76 resource/spec-example tests were rerun after provider-reference/capability alignment.Earlier provenance/revocation evidence remains: focused compiler/real CLI suites, 65 provenance runtime tests, standard Go lint, 345/345 workflows compiled, and independent merged-revision drift checks.
smoke-security-alertsretains exclusive source scopes, provenance/admission configuration references, read-only alert access, no user checkout/external agent network, and noop output.Whole-branch limitation: 18 pre-existing custom-lint findings in
safe_outputs_app_config.go(two function-length, 16 indexing) were reproduced against exact pre-change source usinggo vetoverlays. Earlier debt also includescompiler_pre_activation_job.goand inherited actionlint/shellcheck limitations. Scoped success is not a clean whole-branch/full-suite claim.Security inventory and rollout boundary
Previously added secret references
GH_AW_GATEWAY_APP_IDandGH_AW_GATEWAY_APP_BOT_IDare public numeric identities used only by the compiler-owned GitHub metadata verifier. The current compiler update addsGH_AW_GATEWAY_GET_TOKEN_URLandGH_AW_GATEWAY_OIDC_AUDIENCE, protected service configuration used only by the trusted admission job, with matching Actions-variable fallback. All four were reviewed: none is a private key or dispatch-token source, and manifest inventory exposes names rather than values.Removed secrets: none. New/removed Actions: none. Existing SHA-pinned actions are reused. App provenance retains its authenticated GitHub identity lookups. Hash admission presents the OIDC token only to the independently approved HTTPS endpoint, without reading a repository token or fetching the compiled file on the runner. All new calls disable redirects and automatic retries, bound request/response sizes, and redact error bodies. Runtime token actions retain explicit post-job revocation. No deployed secret values, grants, ownership, or enrollment state were read or changed.
Deployment review remains required: the actual endpoint/audience/issuer enrollment, independent backend JWT/artifact verification, dispatch-table refresh, and current source/destination grants cannot be established by compiler tests or mock servers. A configured endpoint returning approval without those checks is not a conforming backend.
No deployment/rollout is included: no live dispatch/workflow run, hosted acceptance, receiver activation, source enrollment, credential grants, central secret/variable changes, or rollout-policy changes. Compiler opt-in and local reference implementations do not authorize a receiver or prove live acceptance.