Skip to content

GitHub evidence contract

The read-only collector accepts an enrolled GitHub repository name and a server-supplied credential. It makes read-only REST and GraphQL requests only to the fixed GitHub API origin, rejects redirects, and emits a minimized typed result. Repository metadata, the default-branch head, CI, and security have separate coverage states. A successful fetch is not the same as healthy repository evidence.

Evidence scope

CategoryRead scopeMeaning of an empty result
RepositoryThe enrolled repository's metadataInvalid response, not a missing repository record
HeadThe default branch's commitUnverified CI reference
ChecksAggregate Check Run state counts for the observed commitNo Check Run evidence
StatusesAggregate commit-status state counts for the observed commitNo commit-status evidence
DependabotOpen repository alertsNo open alerts in the complete supported collection
Code scanningOpen alerts on the default branchNo open alerts in the complete supported collection
Secret scanningOpen alerts with literal values hiddenNo open alerts in the complete supported collection

CI is passing only when the complete status rollup contains an actual success and no pending or unsuccessful result. The collector validates the enrolled repository, exact observed commit, separate category totals, unique state counts, and combined total before accepting the rollup. Empty rollups, skipped-only checks, pending work, malformed results, and unavailable evidence cannot establish passing CI. The collector reports aggregate checks and statuses, not individual run details, branch-protection, or ruleset compliance. Failed results remain actionable when another category is unavailable.

A zero finding count requires complete reads of all supported security categories. Partial collections can report a positive lower bound, but cannot establish that the repository is free of findings. Repository assessment keeps incomplete security coverage visible alongside known findings. Scanning coverage is limited to what GitHub returns through these endpoints; it is not proof that every vulnerability or secret has been detected.

Repository metadata can explicitly mark individual security scanners as not required. This changes the coverage warning and security expectation, while the collector still attempts every supported category and preserves its original result. Required security results need observed per-category counts; a missing count remains unknown. Unrequired categories cannot conceal positively observed findings. The coverage projection distinguishes requirements_met from complete current coverage, leaves unread states and timestamps intact, and applies source configuration, expiry and repository identity checks before either state. See resolving gaps for the operator workflow.

Safety and bounds

The API version, timeout, response-size, pagination, and request budgets are named in the shared evidence contract. Timeout covers response-body reads as well as request establishment. Cancelled work does not start another request. Endpoint failures return fixed, actionable messages rather than provider response bodies.

Dependabot pagination uses cursors. Other supported list endpoints can use page or cursor links. A next link must retain the fixed origin, enrolled endpoint, and requested filters; credential-bearing redirects, extra parameters, duplicate cursors, filter changes, repeated pages, overlapping results, and inconsistent totals do not establish complete coverage. Hitting a collection budget produces a limited result, not an empty success. Rate-limit responses produce a retry deadline with a bounded backoff; the durable refresh layer owns scheduling that retry across sources.

Secret-scanning requests include hide_secret=true. Literal values and other unneeded fields are discarded even if a provider returns them despite that flag. Only allowlisted evidence enters the result. Provider error bodies, repository descriptions, commit messages, arbitrary links, and credential values are not returned or journaled. Evidence links are constructed from the fixed GitHub web origin and enrolled repository name.

Observation time belongs to the collection, not the browser refresh or later database receipt. Persisting, retrying, or displaying a result must not extend its freshness. A source's declared policy determines the expiry.

Source ownership and credential custody

Each GitHub source belongs to one workspace and an explicit set of enrolled repositories. Owners control its name, enabled state, credential reference, refresh interval, and freshness window. Settings use optimistic revisions; conflicting edits leave the browser draft intact. A name-only edit preserves valid evidence. Removing a repository excludes its old observations; disabling a source or changing its credential reference expires existing evidence. Shortening freshness may shorten an existing expiry, but extending the policy or re-enabling a source cannot revive old evidence. Any settings revision cancels in-flight work that was bound to the preceding revision.

The dedicated Worker secret binding GITHUB_CREDENTIALS contains an object keyed by credential reference. Each entry has exactly workspaceId, a human-readable name, and a server-only token. Invalid entries are unavailable. Credential discovery returns only references and labels belonging to the authorized workspace, and requires owner access. GitHub does not use the generic provider CREDENTIALS map. Token values are never accepted by browser forms, ordinary API commands, CLI arguments, or MCP tools, and are not stored in D1. D1 retains an internal credential digest for job identity and cooldown coordination, never in routine responses.

Provision only read access to the selected repository metadata, default-branch head, aggregate CI rollup, and supported alert endpoints. Supported token types and exact permissions must be checked against the linked GitHub endpoint contracts when provisioning. Inaccessible or disabled security features remain unavailable, not clear. Supplying a token with broader permissions does not broaden the collector: it still sends only the fixed allowlisted reads.

Provision the catalog through the deployment platform's secret-input boundary, using protected standard input or its privileged secret manager. Do not place it in source-controlled configuration, frontend environment variables, logs, or screenshots. To rotate safely, disable affected sources first, rotate their deployment binding, then re-enable the sources. Already-running Worker invocations retain their environment snapshot; the disabled source revision in D1 is what invalidates their results immediately. The same provider token used under multiple references or workspaces shares a digest-keyed cooldown.

Durable execution and recovery

Refresh intent, actor identity, source revision, pinned repository identities, and item receipts are persisted before any external read. Duplicate refresh IDs return the original receipt to the same actor for the same source and revision. Conflicting reuse is rejected. Only one refresh may be active per source. Manual refreshes have a minimum interval, and provider cooldowns can extend the wait. An active manual job rechecks the requesting member's operator authority and bearer credential validity at claim and acceptance; scheduled work instead derives authority from the owner's enabled workspace source configuration.

Workers claim an item with an expiring lease and recheck source revision, enabled state, repository scope and identity, actor authority, provider credential identity, and lease ownership before accepting it. D1 batches atomically record outcomes and evidence. A stale lease, revoked actor, cancelled job, renamed repository, or incompatible source cannot overwrite evidence. Observation ordering prevents an older read from replacing a newer one. Workspace evidence capacity is enforced at the same write boundary; a capacity failure is visible in the receipt instead of breaking the workspace snapshot.

HTTP requests schedule a bounded background slice with waitUntil; the persisted queue survives interruption of that slice. The production Cron handler recovers interrupted leases, schedules due sources, drains bounded work, and performs a final recovery pass without a browser or local machine. Named limits in shared/github.ts bound source scope, intervals, per-invocation work and time, retries, recovery age, and history. A source can select up to one hundred repositories. Scheduled slices process at most twenty repositories sequentially within a two-minute wall budget, including scheduler setup. The runner does not claim another repository without reserving its twenty-second collection deadline plus a five-second acceptance margin. Database delays can still consume that margin; leases and acceptance checks remain authoritative. HTTP background slices remain limited to one repository and twenty-five seconds.

Each paginated endpoint allows five pages of up to one hundred entries. Three scalar reads plus three paginated endpoints yield a maximum of eighteen GitHub requests per repository, or 360 per complete scheduled slice. This profile requires Workers Paid; it deliberately exceeds the Free external-request allowance and has observed CPU usage above Free's allowance. See the compatibility record for measured and projected CPU, request, database, and logging usage. Increasing the deployment's CPU ceiling to five minutes is unnecessary for this profile.

Unprocessed repositories remain queued for subsequent invocations. Cron runs on a fixed eligibility cadence, not a guarantee that every repository completes at its configured interval; source intervals and freshness should allow for the total enrolled workload. A fifty-repository fixture drains across three ordinary scheduled slices, but slow providers, deeper pagination, additional sources, and recovery can extend that drain. Repeated interruption exhausts attempts; over-age jobs terminate visibly. Provider rate limiting leaves unread items queued until cooldown ends, while the rate-limited item's incomplete evidence remains explicit. A new refresh is required to reread that item.

GitHub quotas remain independent of the Cloudflare plan. GitHub documents a shared personal-token allowance of 5,000 requests per hour; fifty repositories at six requests each every five minutes project 3,600 requests per hour before other applications or manual refreshes. Repeated full pagination projects 10,800 requests per hour and cannot sustain that cadence on this allowance. Increase source intervals when measured demand requires it, retain cooldowns, and inspect partial receipts instead of assuming Paid removes provider limits. These are workload projections, not measured hourly consumption. See GitHub's rate-limit contract.

Enabled release profiles invoke the scheduler every minute to drain these small batches. This is not a per-source refresh interval: persisted source settings determine when new reads become due, and an unfinished refresh continues without creating duplicate work. Disabled release profiles have no Cron trigger.

Saving source settings does not bypass the minimum interval after the previous refresh attempt. The scheduler leaves that source eligible for the next permitted tick without recording a collection failure or imposing a longer default delay. Concurrent source edits, disablement, removal, accepted refreshes and shared provider cooldowns are rechecked without replacing an earlier genuine error. Invalid configuration and unavailable credentials still produce explicit source errors; unexpected scheduler failures still reach invocation diagnostics. The retry deadline remains visible in the source's provider-cooldown status.

Completed job items preserve partial and failed results. lastSuccessAt advances only after complete collection across the selected repositories; it is not a health assertion. A failed read replaces that source's passing claim with unknown or incomplete evidence instead of freshening it. Manual starts and terminal outcomes are journaled. Scheduled outcomes are journaled when evidence or source error state changes, not for identical heartbeat reads. Completed historical receipts expire after the retention window, except for a source's latest receipt; Activity is retained separately. A refresh ID is not a permanent idempotency key after its receipt expires, so long-delayed clients should inspect history before submitting new work.

Bounded coverage reads

Release and deployment context is a separate bounded on-demand read. It reuses enrolled read credentials without adding endpoints to scheduled CI/security refreshes or changing the observation health contract.

github_coverage is a read-only workspace contract shared by the browser, CLI and MCP. It accepts unique explicit repository IDs bounded by GITHUB_COVERAGE_LIMITS.REPOSITORIES and an optional exact source ID. It returns repository identity/revision, currently enrolled GitHub source metadata, accepted check coverage with original observation/receipt/expiry times, and each source's latest refresh item for the selected repository. Rows preserve requested repository order. A selected source that exists but does not enroll a requested repository contributes no coverage; a source or repository outside the workspace is unavailable, not an inferred association.

The projection also returns normalized scanner requirements, per-check required flags and fixed guidance for unavailable required checks. Guidance is deduplicated by the supported check keys and contains no provider-supplied text or credential references. Repository requirements use the existing authorized, revision-checked repository_update contract and its Activity attribution. Coverage reads revalidate the repository revision along with source revisions, so a requirement edit cannot silently change the meaning of an in-progress read.

The latest-run item is not a query for the latest attempted item across all retained history. Its attempt count distinguishes a queued or cancelled-before-attempt item from actual collection, independently of the last accepted observation. Source-revision and repository-name matches qualify the receipt; an old name also makes accepted evidence unsuitable for the saved repository identity. Complete read coverage is independent of observed CI failures and security findings. Unavailable, unobserved, error, limited and rate-limited checks remain distinct. Missing check keys cannot become observed by omission.

The implementation batches bounded local metadata, scope, evidence and latest-item reads, then revalidates live principal authority and repository/source revisions. Reader access is sufficient; publisher and Reporter credentials remain excluded. It resolves only safe server-side credential availability metadata and cooldowns, with no provider requests. Raw payloads, credential references or values, check summaries and unrelated observation fields are excluded from this projection. Stored malformed evidence or receipt metadata fails explicitly. Named source-row and UTF-8 response bounds fail closed with guidance to narrow the selection.

The Coverage screen derives filters and pagination from its existing tab-scoped repository/source/evidence records. Only visible repository IDs request latest-item details. Source or repository changes invalidate that active auxiliary read; Activity-only updates do not. Connections and other tabs do not keep the coverage query mounted. A local display clock ages evidence without fetching it, and hidden tabs stop the clock. Failed reads preserve the workspace evidence display with an explicit error and retry, rather than rendering an empty or healthy result.

Dependabot schedule observations

The schedule timeline uses a dedicated per-enrollment cache and an explicit fixed-path reader. It is separate from scheduled CI/security collection and does not add provider calls when the timeline opens. A complete inspection uses at most five GETs: repository identity/default branch, branch head/root tree identity, nonrecursive root tree, nonrecursive .github tree, and the selected immutable blob. Complete tree coverage is required to establish absence. Symlink modes, truncated trees, duplicate paths, invalid UTF-8, mismatched Git blob identities, oversized responses, or both filenames never become an accepted editable schedule.

The reader shares contextual-read leases, the five-minute cache interval, the per-credential inspection budget, and provider cooldowns. Read authority is rechecked after provider I/O, credential hashing, and notification delivery. Inventory pages carry a workspace revision so a client can detect concurrent repository or enrollment changes. Only normalized schedules and safe file/commit identities are retained; no raw YAML, registry settings, private provider response bodies, or credential values are exposed. Review preparation consumes the shared read budget for a separate immutable-blob proof. Final submission re-inspects through the reviewed repository writer under the bounded operation-start budget.

Schedule projection runs in the client with explicit IANA zones and rejected DST ambiguities. Freshness, unsupported representations, and loading/projection limits qualify overlap coverage independently of the provider read state. The resource record separates those application bounds from Cloudflare quotas.

Deployment and verification boundary

The repository's production configuration declares the scheduled handler but uses placeholder storage identity and does not provision authentication or provider credentials. Deployment must deliberately configure the real D1 database, apply migrations, establish workspace membership and authenticated access, install the dedicated GitHub binding, and verify the Cron trigger before enabling production sources. Preserve D1 through the provider's backup/recovery path and the credential catalog through a separate protected secret recovery path. Restoring only source code does not restore memberships, receipts, observations, or secrets. The retained hosted deployment is not modified by running this preview.

Collector and durable-job tests exercise the local Workers/D1 runtime with isolated GitHub responses and synthetic credentials. The actual scheduled handler and production bearer-authenticated HTTP background path are fixture-tested. Browser tests use real isolated source-setting writes and explicit synthetic refresh receipts to verify progress, incomplete evidence, cancellation, role-specific controls, conflicts, retry behavior, and accessibility. These checks do not claim that production credentials, private repository permissions, or a deployed schedule have been validated.

References

The REST endpoint and parameter shapes follow GitHub's published REST OpenAPI description. CI semantics follow the GraphQL commit status rollup and Check Run states. Security reads use the Dependabot alerts, code-scanning alerts, and secret-scanning alerts contracts.