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
24 changes: 24 additions & 0 deletions .github/workflows/cao.json
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,30 @@
},
"repository": "github/gh-aw",
"workflow": "daily-file-diet"
},
{
"api-requests": 111,
"acquisition": {
"requirements": [
{
"cache": "invocation",
"pool": "core",
"primitive": "github.dependabot-alert-lifecycle.v1",
"scope": "github/gh-aw",
"source": "github"
},
{
"cache": "invocation",
"pool": "search",
"primitive": "github.dependabot-pull-request-lifecycle.v1",
"scope": "github/gh-aw",
"source": "github"
}
]
},
"collector": "dependabot/operational-value/dependabot-update-planner.mjs",
"repository": "github/gh-aw",
"workflow": "dependabot-update-planner"
}
]
}
Expand Down
48 changes: 23 additions & 25 deletions ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -1926,24 +1926,16 @@ not authorize cross-repository evidence access.
Host-neutral source builds use `server/Dockerfile` with explicit version and
revision build arguments; deployment promotion and rollback belong to the
application host. The source build
produces a lean admission-only dashboard target and a collector target with
Node, GitHub CLI, a checksum-verified policy-pinned gh-aw binary, and the
Activity projection catalog. The collector target also generates a
deterministic control-plane inventory from the exact checked-out source and
packages only that inventory plus the shared policy resolver required at
runtime; it does not restore a second editable campaign catalog. Before each
canonical ingestion replacement, a private collection role resolves the reviewed deployment
policy, overlays the exact operational enrollment set, and uses a short-lived
installation token for the control repository to enrich and retain
`control-settings.json`, `control-plane-inventory.json`, and
`inventory-sources.json` in the evidence lake. The first activation fails
closed without valid campaign inventory; a later transient refresh failure
may retain the previous valid inventory. The internet-facing dashboard holds
the webhook secret but no collection private key. Unexposed collector and
idempotent backfill services hold the read-only GitHub App key and share a
persistent evidence volume. The collection profile leaves
`CAO_SOURCE_DIRECTORY` unset, while one verified activity artifact remains an
external read-only recovery volume for rollback to the snapshot profile.
produces a lean admission-only dashboard target and a private Go collector
target with Git for the reviewed Value Git transport, but no Node, GitHub CLI,
gh-aw or Activity projection catalog. PostgreSQL retains the exact reviewed
inventory configuration and source-epoch-bound evidence; collector and
backfill roles share these durable stores rather than an evidence volume.
The internet-facing dashboard holds the webhook secret but no collection
private key. Unexposed collector and idempotent backfill services hold the
read-only GitHub App key. The collection profile leaves
`CAO_SOURCE_DIRECTORY` unset; a separately selected Actions snapshot profile
can still mount a verified activity artifact read-only.
Locally source-built images are not admitted through the package workflow's vulnerability scans,
hardening check, SBOM, or artifact attestations; those guarantees continue
to apply only to published packages.
Expand Down Expand Up @@ -1976,15 +1968,19 @@ not authorize cross-repository evidence access.
Webhook/control deliveries carry source epochs and fresh queue receipts.
Independent safe-output dispositions survive run reprojection, while durable
Value invalidations remain hints, not acquired Value evidence.
The separately selected `NativeValues` lane reuses reviewed Node Value
programs and therefore still requires its catalog and policy assets. Its
The separately selected `NativeValues` lane evaluates the reviewed Value
policy and supported collector in Go, using Git only for its declared Git
acquisition requirements. Optimization uses the canonical PostgreSQL query
boundary; the separately registered Dependabot collector acquires bounded
alert and pull-request lifecycles through the shared native quota bridge
and publishes three atomic cutoff packets. The local evaluator consumes
their canonical facts; incomplete cutoffs remain missing, never zero. Its
private invocation scratch is disposable: PostgreSQL restores the original
source-epoch-bound packet/proof snapshot, fences publication against that
starting packet, and erases private proof/publication ownership atomically on
withdrawal. Those selected-feature dependencies are not dependencies of native
run acquisition, projection or trace admission. The existing remote Value
transport remains Linux-only; local query execution has its separate owned
canonical PostgreSQL boundary.
run acquisition, projection or trace admission; local query execution has
its separate owned canonical PostgreSQL boundary.
Native archive admission binds the original dispatch epoch before lossy
normalization. Its PostgreSQL metadata-only privacy ledger withdraws visibility
with source ownership and durably retries epoch-specific Blob retirement;
Expand All @@ -2003,8 +1999,10 @@ not authorize cross-repository evidence access.
exercise real PostgreSQL, replica restoration and worker execution without an
executable PATH or legacy files. Doctor shares native setting and selected
Value dependency validation, and does not probe legacy lakes or projection
locks for native deployments. Existing hosted/container defaults remain
the separate legacy producer.
locks for native deployments. App-backed collection without native selection
now fails at startup; only the no-App Actions snapshot profile remains the
default. Unsupported Value collector registrations fail closed rather than
launching the former JavaScript runtime.
See `specs/server-ingestion.md` section 2.4.
- Browsers and external clients never receive Redis or Postgres endpoints or
credentials. Dashboard source replacement is transactional in Postgres; a
Expand Down
18 changes: 18 additions & 0 deletions dependabot/operational-value/dependabot-update-planner.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,24 @@ export const definition = {
zeroRule: "Complete lifecycle evidence with no alert or pull request open at the cutoff records zero.",
missingRule: "Inaccessible, truncated, malformed, or incomplete lifecycle evidence records missing rather than zero.",
},
acquisition: {
requirements: [
{
source: "github",
pool: "core",
primitive: "github.dependabot-alert-lifecycle.v1",
scope: "github/gh-aw",
cache: "invocation",
},
{
source: "github",
pool: "search",
primitive: "github.dependabot-pull-request-lifecycle.v1",
scope: "github/gh-aw",
cache: "invocation",
},
],
},
model: {
architecture: "Problem-first repository-risk measurement independent of gh-aw outputs, recommendations, runs, and engagement.",
recommendation: "Use total open Dependabot security alerts as the primary outcome and retain critical/high alerts and the Dependabot pull-request queue as separate diagnostics. Count improvement regardless of actor and describe adoption-timed movement as association.",
Expand Down
47 changes: 34 additions & 13 deletions docs/deployment-azure.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ digests, and locks the version-plus-config-hash tags against writes and deletes.
It then deploys the full template with separate Functions, provisioning, and
ingestion digest parameters, not those tags. After deployment it reads back the
configured digest references for all three targets before starting either job;
missing, mismatched, or additional job containers fail closed. Regenerate
`server/azure/main.json` from the current Bicep source before planning: apply
rejects templates without the three digest parameters before any Azure call.
missing, mismatched, or additional job containers fail closed. Regenerate `server/azure/main.json` from the reviewed Bicep sources before
planning, then review the exact compiled template. Apply rejects templates
without the three image digest parameters before any Azure call.
New managed-identity Key Vault grants can take time to propagate. Apply retries
the exact reviewed ARM request at most three times only when every nested
failure is the recognized job secret-fetch error in the ingestion or
Expand Down Expand Up @@ -988,23 +988,44 @@ You configure traces for orchestrators and workers separately, in the control re

## Using the optional collection profile

By default, the server serves the data that the Activity workflow publishes and doesn't collect anything itself. To have Azure collect the data instead, set the `collectorImage` parameter. The `server/azure/collector.bicep` template then adds:
By default, the server serves the data that the Activity workflow publishes and
doesn't collect anything itself. To have Azure collect instead, set
`collectorImage` to an image built from the reviewed `collector-runtime` Docker
target and supply `collectorNativeInventoryDigest` at deployment. The
authoritative `server/azure/main.bicep` and `server/azure/collector.bicep`
sources compile to `server/azure/main.json`. The optional module adds:

- Workers and backfill in the same private Container Apps environment as ingestion.
- A fixed number of collection workers sharing the PostgreSQL operational queue. Set `collectorWorkerReplicas` to the required replica count; the default is `1`.
- A fixed number of native Go collection workers sharing the same deployment-scoped PostgreSQL operational queue as the Function App. Set `collectorWorkerReplicas` to the required replica count; the default is `1`.
- A backfill job.
- A user-assigned managed identity with access to Key Vault and `AcrPull` on this deployment's registry. Build the collector image into that registry.
- An Azure Files share for collected evidence. The SKU is set by `collectorLakeStorageSku` (default `Premium_LRS`).

The optional evidence lake requires a separate file-storage account with shared
access across workers and evidence-retention settings; Functions runtime storage
has different access requirements. With collection disabled, the baseline
creates only one storage account. It never creates a second Insights component
No evidence lake or Azure Files mount is used by native acquisition. The
baseline and optional collector do not create an additional Insights component
or workspace.

The collection profile requires these parameters: `collectorGithubAppId`, `collectorPrivateKey`, `githubWebhookSecret`, `githubAdminUsers`, and `collectorControlRepository`.

In this profile, the Function App only admits webhooks (`CAO_COLLECT_ADMIT_ONLY=true`). It verifies and deduplicates deliveries to `POST /api/github/webhook`, then queues the work. It never holds the app's private key.
The collection profile requires `collectorGithubAppId`, `collectorPrivateKey`,
`githubWebhookSecret`, `githubAdminUsers`, `collectorControlRepository`, and
`collectorNativeInventoryDigest`. Provision the exact immutable reviewed
inventory bytes using `Acquisition.PinInventoryConfiguration` in the shared
canonical PostgreSQL dataset namespace (`azure-dashboard` by default)
**before starting workers**; the Azure template does not generate or
provision that snapshot, and this guide does not provide an automated
inventory-provisioning command.
Supply its lowercase SHA-256 digest, not a local inventory path or an
automatically discovered inventory. A missing digest fails optional-module
parameter validation; an invalid, unprovisioned, or mismatched digest fails
worker startup rather than using another snapshot or falling back to Actions.
The image must include `/app/cao-dashboard` and
`/app/queries/database.json`. The separate Value lane is not enabled by
this template (`CAO_COLLECT_NATIVE_VALUES` is unset).

In this profile the Function App selects `CAO_COLLECT_NATIVE=true` but only
admits webhooks (`CAO_COLLECT_ADMIT_ONLY=true`). It verifies and deduplicates
deliveries to `POST /api/github/webhook`, then queues the work in PostgreSQL.
It never holds the app's private key or requires inventory bytes. Workers and
backfill select native acquisition with the same operational namespace and
the exact reviewed digest.

The approved ingress path must also permit GitHub webhook delivery. Disabled
public access or client-only allow rules can block it; do not widen access just
Expand Down
36 changes: 29 additions & 7 deletions docs/operational-value.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,16 +147,16 @@ capture. Ordinary Activity projection and bounded local Value remain
independent. The default Actions profile has no inbound webhook receiver and
continues its existing scheduled collection.

The hosted worker keeps the installation token outside the collector process.
Its repository-confined API bridge admits REST/core, search and GraphQL
The hosted Go worker keeps the installation token out of policy, packets and
private proof. Its repository-confined API bridge admits REST/core, search and GraphQL
requests against the same shared installation quota used by Activity; GraphQL
is limited to the reviewed File Diet query shape and its points are accounted
separately from the reviewed API request count. Unsupported query shapes fail
closed rather than extending a registration's authority. Missing
quota evidence, exhausted capacity, changed policy/enrollment, incomplete
collection or superseded accepted evidence defers publication. On success
only the validated original packet is atomically published to PostgreSQL.
Private per-pair proof retains the last 30 attempts' API request count, wall
only validated original packets are atomically published to PostgreSQL.
File Diet's private per-pair proof retains the last 30 attempts' API request count, wall
time and received/output bytes, including failures, plus cumulative observed
GraphQL points and the number of requests whose point cost could not be
verified. An unknown point cost is not reported as zero; quota preflight is
Expand All @@ -174,7 +174,7 @@ invalid result leaves previous evidence and its capture/cutoff timestamps intact
it is not a fresh success or zero. Explicit operator evaluation and one-time
publication remain separate, subject to their existing authority and budgets.

Collector subprocess failures cross runtime boundaries only as bounded categories:
Collector failures cross runtime boundaries only as bounded categories:
`api-budget`, `budget-unavailable`, `timeout`, `output-budget`, or
`collector-failed`. Worker markers cannot supply `output-budget`; that category
is owned by the host enforcing its output limits. Unknown markers and raw stderr
Expand Down Expand Up @@ -218,12 +218,34 @@ retime either clock.

The control policy explicitly lists the same six repositories previously
collected from `scope.allowed-repositories`; this pins Activity enrollment
without adding targets or activating Daily File Diet itself. Only the exact
File Diet pair is registered for recurring Value acquisition.
without adding targets or activating Daily File Diet itself. Only the File Diet and Dependabot Update Planner pairs in `github/gh-aw` are
registered for recurring Value acquisition.
Registration is visible after the collector and policy are reviewed and
deployed together. Its reviewed `api-requests: 700` ceiling allows Activity to
refresh it automatically only when that full grant fits above ordinary
collection's protected reserve.

### Dependabot lifecycle collector

The separately reviewed `dependabot-update-planner` registration covers only
`github/gh-aw`. Its Go collector follows bounded alert `after` cursors for
closed and open Dependabot security-alert lifecycles (at most 100 pages) and Dependabot-authored pull-request search
results (at most ten pages) through the installation's shared Core and Search
quotas. At 100 records per page, the reviewed ceiling is 111 metered
requests (100 alert pages, ten search pages, and one optional Search-quota
preflight); exceeding either bound, the search-result cap, or the timeout is
missing evidence, not an empty queue. The installation needs Dependabot-alert
and pull-request read permissions for that repository; lacking either defers
collection without changing accepted observations.

Three packets, one for each frozen metric, commit atomically with the private
proof after complete acquisition. The local Go evaluator queries only those
canonical packets for the aligned seven-day cutoff. It emits numeric open
alert, critical/high-alert, and Dependabot PR counts when all three are
complete, including genuine zeroes; otherwise it emits missing measurements
and preserves earlier accepted captures. This registration does not change
the Dependabot campaign's rollout mode or grant another repository access.

It does not override `campaigns.dashboard.deploy: false`:
this repository intentionally disables standalone Pages deployment because
Documentation Pages owns the combined site. The existing publication chain is
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/githubnext/gh-cao/internal/dashboardquery v0.0.0
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
golang.org/x/sys v0.49.0
golang.org/x/term v0.47.0
golang.org/x/text v0.43.0
modernc.org/sqlite v1.60.1
Expand Down Expand Up @@ -73,7 +74,6 @@ require (
golang.org/x/net v0.61.0 // indirect
golang.org/x/oauth2 v0.36.0 // indirect
golang.org/x/sync v0.24.0 // indirect
golang.org/x/sys v0.49.0 // indirect
golang.org/x/time v0.15.0 // indirect
gonum.org/v1/gonum v0.17.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
Expand Down
Loading
Loading