Skip to content

Keyboard shortcuts

Go

  • Scope — the control cataloggm
  • Plan — your last certification classgp
  • Collect — the recipe indexgc
  • The control you are workinggw
  • Startgh

Move

  • Next rowj
  • Previous rowk
  • Previous in this run[
  • Next in this run]
  • Filter this page's list/
  • Search everythingK

Act

  • Copy this page's permalinky
  • Toggle dark moded
  • This sheet?

Rows are whatever the current page lists — controls on Scope, recipes on Plan and Collect.

Control index

Whether Dependabot alerting is configured in this organization and which repositories it actually reaches, together with the alerts themselves — each carrying the advisory that raised it, the package, ecosystem and manifest path it was found in, the reason a human gave for closing it, and, for a remediated one, the date it was fixed. The first half is the population; the second half is what was found in it, and the second half means nothing without the first.

The API supplies the facts, but a human judgement against a documented baseline turns them into evidence.

partial — needs judgementapicontinuousGitHub DependabotGitHub code security configurations

Fetch

$ gh api --paginate "/orgs/<ORG>/code-security/configurations"
$ gh api --paginate "/orgs/<ORG>/code-security/configurations/<CONFIGURATION_ID>/repositories?per_page=100"
$ gh api --paginate "/orgs/<ORG>/dependabot/alerts?state=open&per_page=100"
$ gh api --paginate "/orgs/<ORG>/dependabot/alerts?state=dismissed&per_page=100"
$ gh api --paginate "/orgs/<ORG>/dependabot/alerts?state=auto_dismissed&per_page=100"
$ gh api --paginate "/orgs/<ORG>/dependabot/alerts?state=fixed&per_page=100"

Expected output

Report names used below, and the command each comes from: `configurations` is the first command, `configuration-repositories` the second, `alerts-open` the third, `alerts-dismissed` the fourth, `alerts-auto-dismissed` the fifth, `alerts-fixed` the sixth. RUN THE SECOND COMMAND ONCE PER CONFIGURATION returned by the first, not once for the organization. The first command returns every configuration and the second takes a single `<CONFIGURATION_ID>`; collecting one response and reading it as the organization's is the arithmetic error this recipe is most likely to be assessed with, and the clause on `configuration-repositories` speaks only for the configurations actually walked. From the configurations call, an array of code security configurations, each with an id, a name, a `target_type` of `global`, `organization` or `enterprise`, and the feature fields as THREE-STATE strings rather than booleans — `dependabot_alerts`, `dependabot_security_updates`, `dependency_graph`, `secret_scanning`, `secret_scanning_push_protection`, `code_scanning_default_setup` and `private_vulnerability_reporting` each taking `enabled`, `disabled` or `not_set` — plus an `enforcement` of `enforced` or `unenforced`. `not_set` is the value to read carefully: it is neither on nor off, it is the absence of a decision, and a clause comparing against `disabled` alone does not see it. From the configuration-repositories call, rows carrying a `status` of `attached`, `attaching`, `detached`, `removed`, `enforced`, `failed`, `updating` or `removed_by_enterprise` and the repository object each refers to; the call passes no status filter, so a failing row is present-and-false rather than absent. From the alerts calls, alerts with `number`, a `state` of `open`, `dismissed`, `fixed` or `auto_dismissed`, a `severity` of `low`, `medium`, `high` or `critical`, a `dependency` object naming `package.ecosystem`, `package.name`, `manifest_path`, a `scope` of `development` or `runtime` and a `relationship` of `direct`, `transitive`, `inconclusive` or `unknown`, a `security_advisory` object carrying `ghsa_id`, a nullable `cve_id`, `cvss_severities` with `cvss_v3` and `cvss_v4` scores, `cwes`, a `classification` of `general` or `malware` and `epss` percentage and percentile, a `security_vulnerability` with the affected version range, `created_at`, `updated_at`, `dismissed_at`, `fixed_at` and `auto_dismissed_at` timestamps, a `dismissed_reason` from the enum `fix_started`, `inaccurate`, `no_bandwidth`, `not_used` and `tolerable_risk`, and the `repository` the alert belongs to. Note the calls that look like one: `dismissed`, `auto_dismissed` and `fixed` are SEPARATE values of `state`, so a query for any one returns none of the others. The organization endpoint requires an organization owner or a security manager, and a token carrying the `security_events` scope.

Assertions — what makes it a pass

Assertions for Whether Dependabot alerting is configured in this organization and which repositories it actually reaches, together with the alerts themselves — each carrying the advisory that raised it, the package, ecosystem and manifest path it was found in, the reason a human gave for closing it, and, for a remediated one, the date it was fixed. The first half is the population; the second half is what was found in it, and the second half means nothing without the first.: the field checked, the condition it must satisfy, the rows it applies to, and the controls a pass proves.
FieldMust beForProves
configurations[?target_type=='organization' && dependabot_alerts=='enabled'] | [0].idexistsAt least one code security configuration the organization itself owns sets `dependabot_alerts` to `enabled`. The field is three-state and the middle value is the trap: `not_set` is neither on nor off, and a clause written against `disabled` passes an organization that never decided. `target_type` is narrowed to `organization` because the enum admits a `global` scope no administrator creates. This says a configuration exists and decided; it does not say which repositories it reaches, and it does NOT say nothing is scanned when it fails — repository-level enablement bypasses configurations entirely. Read it with the clause below and with the reconciliation `scan_scope` names.every rowSR-06
configuration-repositories[?status=='failed']count_eq 0No repository the configuration was applied to failed to receive it. `failed` is the status that produces silence rather than an error: the repository is attached in intent, collects nothing, and contributes no row to any alert query — so an alert list over the organization is partly clean BECAUSE of it. The call passes no status filter, so the failing row is present-and-false rather than absent, which is why the offender form works here. It speaks only for the configurations actually walked; see the iteration note in `expected_output`.every rowSR-06
configurations[?target_type=='organization' && dependabot_alerts!='enabled']count_eq 0No configuration the organization owns leaves Dependabot alerting unenabled. `!=` rather than `== 'disabled'` on purpose: the field is three-state, and `not_set` — a configuration that decided nothing — is the value a comparison against `disabled` walks straight past. The failing row is present-and-false in the same response the clause above reads, which is what makes this the offender form and not a projection over the rows that already pass. A deliberate exception, such as a configuration governing archived or public repositories, fails this clause correctly: it is a finding that wants a written justification, not a defect in the check.every rowSR-06

Authored opinion, like the commands. Units live in the operator name — max-age-days is days, and nothing here is converted for you.

Map — what it proves

  • recipe1
Key Security Indicators
NIST 800-53 controls
  • recipean authored recipe collects evidence for this control
  • KSI onlya Key Security Indicator reaches it, but no recipe is authored yet
  • orphanno Key Security Indicator reaches it — a person writes it up instead

What else these families can fetch:SR 3/14

Outside the boundaryGitHub Enterprise Cloud

Collecting this evidence puts the code-hosting and scanning platform inside the assessment rather than beside it. The repositories, the dependency graph and the alert store are held and operated by a third party, so the platform is itself an information resource whose potential impact has to be addressed under SA-09 and CA-03 and accounted for in the external-system inventory AC-20 already covers — the plane that answers a supply-chain control raises supply-chain controls. Ask the cited Marketplace listing one question in particular before relying on this recipe: SR-06 is a class c and class d control, so every reader of it is running a Moderate or High system, and the impact level a platform's listing carries is not necessarily the one those systems need. That is the SA-09 question here, it is answered by reading the listing rather than by this sentence, and no value for it is written down because it is a dated fact that changes. Which offering is in use decides the rest: GitHub Enterprise Cloud, GitHub Enterprise Cloud with data residency and github.com are different deployments on different infrastructure, and this recipe was authored against the first.

Notes & assertions

SR-06 asks the provider to ASSESS AND REVIEW the supply chain risk associated with suppliers and contractors. This output assesses one population — the third-party software components resolved into the build — continuously, and it produces a reviewable record for each finding. That is a real answer to one limb and it is not the control. Provenance, contract terms, geographic and financial exposure, and the frequency at which a supplier is re-reviewed are a human record, and a manifest entry names a package, not a supplier's risk posture. The disposition this recipe spends said exactly that, and the rating is unchanged by having written the commands down. What the population is, and what it is not. GitHub documents that when Dependabot alerts are enabled it "immediately generates the dependency graph and creates alerts for any vulnerable dependencies it identifies", so the graph is not a separate switch a clause below needs to police — which is why the first assertion reads `dependabot_alerts` and not both fields. What the same page says under its own heading of limitations, and what bounds this recipe more than anything else in it, is that "only advisories reviewed by GitHub trigger alerts". The detection surface is the GitHub Advisory Database's reviewed set. A vulnerability that is real, published, and not in that set produces no alert, and an empty list is silent about it. A second, sharper limit sits inside the first: alerting on MALICIOUS packages, as opposed to vulnerable ones, is a separate opt-in that has to be enabled after Dependabot alerts are, and no command in this recipe can see whether it is on — the code security configuration response carries no property for it. So an alert list with no malware finding in it is equally an organization with no malicious dependency and an organization that never switched the detection on, and a clause asserting the absence of malware would be vacuous for exactly that reason. Both limits are ceilings on the evidence rather than defects in the collection, and they belong in the assessment rather than in a footnote. A code security configuration is not the only way Dependabot gets switched on, and the first clause below is wrong in one direction because of it. Alerts can be enabled on a repository directly, in that repository's own settings, with no configuration involved. An organization that never adopted configurations therefore returns an empty list from the first command and FAILS the clause while scanning every repository it owns. Read a failure there as "no organization-level configuration governs this", which is a real and useful finding, and NOT as "nothing is scanned" — the second reading is unsupported and the reconciliation named in `scan_scope` is what distinguishes them. The multi-configuration case, named because the first assertion is weaker than it reads in the other direction too. The clause is satisfied by ANY qualifying configuration, including one applied to no repository at all. The `target_type` narrowing on both configuration clauses is a deliberate trade and it costs something. The enum admits `global` and `enterprise` alongside `organization`, and GitHub ships a recommended configuration that an administrator does not create but DOES apply from the organization's own configurations table — applying it is a decision, and a decision this clause will not count. So the narrowing buys a false FAIL on GitHub's recommended path and on an enterprise-applied one, in exchange for not passing on a row the organization never chose. That is the right way round only because of how a failure is to be read, below: not as "nothing is scanned" but as "no configuration this organization owns governs this", which is literally true in the global and enterprise cases too. What documentation does NOT settle is whether the org endpoint returns those rows at all — its description says configurations "available in" an organization rather than owned by one — and the live risk is not that the narrowing is unnecessary but that the rows it excludes are the organization's real answer. One call against a live organization settles it, and an assessment leaning on either configuration clause should make that call first. Why there is no clause on `dismissed_reason`. An earlier draft asserted that no dismissed alert had a null reason, and it was decorative: GitHub requires a `dismissed_reason` when an alert's state is set to `dismissed`, so on a `state=dismissed` list there is no documented path that yields null and the clause could not fail. It is recorded here so it is not re-added. The review limb of the claim rests on the fourth command's output being collected and read, not on a check that cannot go red. `state=dismissed`, `state=auto_dismissed` and `state=fixed` are three separate queries, and the last two carry no assertion deliberately. The auto-dismissed list exists because an organization whose alerts close mostly by rule has a short `dismissed` list, and any review clause would be near-vacuously true while very little was reviewed by anyone; an auto-dismissal is a rule firing, not a person deciding, and a clause about its count would assert that a policy is correct rather than that a review happened. The fixed list exists because it is the mitigation record, and it is the reason KSI-SCR-MIT can be claimed at all — but a count of remediated alerts is a measure of how much was broken, not of how well it was handled, and no threshold over it would mean anything without the response clock the plan surfaces separately. It carries the emptiness problem the open list carries, and it carries it while bearing the whole weight of the mitigation claim: an empty fixed list is equally an organization that has never had a vulnerable dependency, one that has never remediated one, and one whose scanning was switched on last week. Nothing in this recipe distinguishes those, which is why the claim on that indicator is a collected record for a human to read and not a check that can go red. MAS-CSO-TPR was deliberately not claimed, and the reasoning is recorded so the next batch does not re-derive it. Its artifact is a machine-readable output of the third-party information resources of the offering, and a dependency IS a third-party information resource on the dataset's own definition — an information resource not entirely inside the Minimum Assessment Scope, where information resources expressly include software and code. But the requirement's statement names the data that output must carry: general usage and configuration, an explanation or justification for use, mitigation measures, and compensating controls. An alert stream carries none of the four, and the enumeration it implies is a by-product rather than the artifact. A recipe that exported the dependency graph SBOM would have a genuine partial claim on that requirement; this one does not, and adjacency is not a join. KSI-SCR-MIT is claimed on the software-component limb only. Identify is the alert, review is `dismissed_reason`, mitigate is the transition to `fixed` — those three are the indicator's three verbs, over one supplier population, and all three are now collected rather than two of them being collected and the third described. Hardware, managed services, and every supplier relationship that never resolves into a manifest are outside it, and an indicator page carrying this recipe should be read as carrying evidence for a part. The evidence platform is itself an external system; see `external_system`. It is not a footnote on this control in particular — SR-06 is a supply chain control, and answering it by adopting a supplier is a move that has to be visible in the assessment rather than only in the recipe.

Scanned population

The repositories inside the authorization boundary, taken from the component inventory the provider maintains for CM-08 and enumerates in its Certification Package Overview — a list held OUTSIDE the platform. Every command in this recipe reads the platform's own view of itself, and the failing case is structurally invisible to every command in it: a repository that is in the boundary and was never attached to a code security configuration, and whose own repository-level settings leave Dependabot off, produces no configuration row, no repository row, and no alert. It is absent, not false. Reconciling the repository ids returned by the second command against that external inventory is the only step in this recipe that can see it, and without that step an empty alert list is equally the output of a well-run organization and of one scanning a third of its code.

  • configurations
  • configuration-repositories

References

This pipeline mapping is authored opinion (overlay v0.8.0), versioned separately from the dataset and written against ruleset 2026.07.14.01. The upstream FedRAMP dataset names none of these tools.

The Supply Chain Risk run (8)

  • automatable
  • partial — needs judgement
  • narrative — no API proves this

Every authored recipe filed under SCR, in the order the plan works them. The mark says how much of the evidence the command produces on its own.