Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Merge remote-tracking branch 'origin/claude/cool-newton-7nm8r9' into claude/cool-newton-7nm8r9 | 1 | /** |
| 2 | * A repository's Security overview: one row per feature, each with a | |
| 3 | * status word, a line of what it does, and the one thing to do about it. | |
| 4 | * Pure, so the rows are tested apart from the page (routes/repo/security-overview.tsx). | |
| 5 | */ | |
| 6 | ||
| 7 | export type FeatureStatus = "enabled" | "disabled" | "needs_setup" | "coming"; | |
| 8 | ||
| 9 | export const STATUS_LABEL: Record<FeatureStatus, string> = { | |
| 10 | enabled: "Enabled", | |
| 11 | disabled: "Disabled", | |
| 12 | needs_setup: "Needs setup", | |
| 13 | coming: "Coming", | |
| 14 | }; | |
| 15 | ||
| 16 | /** The Badge tone each status word is shown in. */ | |
| 17 | export const STATUS_TONE: Record<FeatureStatus, "success" | "neutral" | "warn" | "info"> = { | |
| 18 | enabled: "success", | |
| 19 | disabled: "neutral", | |
| 20 | needs_setup: "warn", | |
| 21 | coming: "info", | |
| 22 | }; | |
| 23 | ||
| 24 | export type RowGroup = "policy" | "findings" | "reporting"; | |
| 25 | ||
| 26 | /** The one thing to do about a feature: a page to open, or a form to post. */ | |
| 27 | export type RowAction = | |
| 28 | | { kind: "link"; label: string; to: string } | |
| 29 | | { kind: "post"; label: string; action: string; intent?: string; pending: string } | |
| 30 | | { kind: "switch"; label: string; intent: string; on: boolean }; | |
| 31 | ||
| 32 | export type OverviewRow = { | |
| 33 | key: string; | |
| 34 | group: RowGroup; | |
| 35 | title: string; | |
| 36 | status: FeatureStatus; | |
| 37 | about: string; | |
| 38 | /** A short hint for the status, shown on hover, when the word alone is not enough. */ | |
| 39 | hint?: string; | |
| 40 | action: RowAction | null; | |
| 41 | }; | |
| 42 | ||
| 43 | export type OverviewFacts = { | |
| 44 | /** Under the project: `/acme/rocket`. */ | |
| 45 | base: string; | |
| 46 | /** Whether a SECURITY.md is on the default branch, and where. */ | |
| 47 | policyPath: string | null; | |
| 48 | /** Private vulnerability reporting. */ | |
| 49 | reporting: boolean; | |
| 50 | /** Published advisories. */ | |
| 51 | advisories: number; | |
| 52 | /** Security updates. */ | |
| 53 | upkeep: boolean; | |
| 54 | codeScanning: { configured: boolean; analyses: number; entitled: boolean }; | |
| 55 | /** Alerts for secrets found in the history. Push protection is always on. */ | |
| 56 | historyAlerts: boolean; | |
| 57 | /** Whether the viewer may change settings (Admin), and push (for the policy's pull request). */ | |
| 58 | canManage: boolean; | |
| 59 | canPush: boolean; | |
| 60 | }; | |
| 61 | ||
| 62 | /** Where a security policy may be: the first found is the one. */ | |
| 63 | export const POLICY_PATHS = ["SECURITY.md", ".github/SECURITY.md", "docs/SECURITY.md"]; | |
| 64 | ||
| 65 | /** The rows, in the order the page shows them. */ | |
| 66 | export function overviewRows(facts: OverviewFacts): OverviewRow[] { | |
| 67 | const { base } = facts; | |
| 68 | const code = facts.codeScanning; | |
| 69 | return [ | |
| 70 | { | |
| 71 | key: "policy", | |
| 72 | group: "policy", | |
| 73 | title: "Security policy", | |
| 74 | status: facts.policyPath ? "enabled" : "needs_setup", | |
| 75 | about: facts.policyPath | |
| 76 | ? `${facts.policyPath} on the default branch tells people how to report a vulnerability and which versions are supported.` | |
| 77 | : "A SECURITY.md on the default branch tells people how to report a vulnerability and which versions are supported.", | |
| 78 | action: facts.policyPath | |
| 79 | ? { kind: "link", label: "View policy", to: `${base}/blob/HEAD/${facts.policyPath}` } | |
| 80 | : facts.canPush | |
| 81 | ? { kind: "post", label: "Set up a security policy", action: `${base}/security/policy/setup`, pending: "Opening a pull request…" } | |
| 82 | : null, | |
| 83 | }, | |
| 84 | { | |
| 85 | key: "advisories", | |
| 86 | group: "reporting", | |
| 87 | title: "Security advisories", | |
| 88 | status: "enabled", | |
| 89 | about: | |
| 90 | facts.advisories === 0 | |
| 91 | ? "Publish what this repository knows about vulnerabilities in what it ships, so people who depend on it can act." | |
| 92 | : `${facts.advisories} published ${facts.advisories === 1 ? "advisory tells" : "advisories tell"} people who depend on this repository what to do.`, | |
| 93 | action: { kind: "link", label: facts.canManage ? "Manage advisories" : "View advisories", to: `${base}/security/advisories` }, | |
| 94 | }, | |
| 95 | { | |
| 96 | key: "reporting", | |
| 97 | group: "reporting", | |
| 98 | title: "Private vulnerability reporting", | |
| 99 | status: facts.reporting ? "enabled" : "disabled", | |
| 100 | about: facts.reporting | |
| 101 | ? "Anyone who can see this repository can report a vulnerability to its maintainers privately, from its Security tab." | |
| 102 | : "Let anyone who can see this repository report a vulnerability to its maintainers privately, instead of in an issue.", | |
| 103 | action: facts.canManage ? { kind: "switch", label: "Private vulnerability reporting", intent: "reporting", on: facts.reporting } : null, | |
| 104 | }, | |
| 105 | { | |
| 106 | key: "dependency_alerts", | |
| 107 | group: "findings", | |
| 108 | title: "Dependency alerts", | |
| 109 | status: "enabled", | |
| 110 | about: "Every package the lockfiles resolve is checked for known vulnerabilities, on every push to the default branch and daily.", | |
| 111 | action: { kind: "link", label: "View alerts", to: `${base}/security/vulnerabilities` }, | |
| 112 | }, | |
| 113 | { | |
| 114 | key: "security_updates", | |
| 115 | group: "findings", | |
| 116 | title: "Security updates", | |
| 117 | status: facts.upkeep ? "enabled" : "disabled", | |
| 118 | about: "A pull request upgrades each vulnerable dependency that has a fix; it lands through the branch's required checks.", | |
| 119 | action: facts.canManage ? { kind: "switch", label: "Security updates", intent: "upkeep", on: facts.upkeep } : null, | |
| 120 | }, | |
| 121 | { | |
| 122 | key: "code_scanning", | |
| 123 | group: "findings", | |
| 124 | title: "Code scanning", | |
| 125 | status: code.analyses > 0 ? "enabled" : "needs_setup", | |
| 126 | about: | |
| 127 | code.analyses > 0 | |
| 128 | ? "Your static analysis tools' results, uploaded as SARIF: alerts on the default branch and a check on pull requests." | |
| 129 | : "Upload your static analysis tools' SARIF results from a workflow: alerts on the default branch and a check on pull requests.", | |
| 130 | hint: !code.entitled ? "On a private repository, code scanning comes with the g1t plan." : undefined, | |
| 131 | action: | |
| 132 | code.analyses > 0 || code.configured | |
| 133 | ? { kind: "link", label: "View alerts", to: `${base}/security/code-scanning` } | |
| 134 | : facts.canManage && code.entitled | |
| 135 | ? { kind: "post", label: "Set up code scanning", action: `${base}/security/code-scanning/setup`, pending: "Opening a pull request…" } | |
| 136 | : { kind: "link", label: "Learn more", to: `${base}/security/code-scanning` }, | |
| 137 | }, | |
| 138 | { | |
| 139 | key: "secret_scanning", | |
| 140 | group: "findings", | |
| 141 | title: "Secret scanning", | |
| 142 | status: "enabled", | |
| 143 | about: facts.historyAlerts | |
| 144 | ? "Push protection refuses every push that adds a secret, and secrets already in the history open alerts." | |
| 145 | : "Push protection refuses every push that adds a secret. Alerts for secrets already in the history are off.", | |
| 146 | hint: "Push protection is always on.", | |
| 147 | action: { kind: "link", label: "View alerts", to: `${base}/security/secret-scanning` }, | |
| 148 | }, | |
| 149 | { | |
| 150 | key: "code_quality", | |
| 151 | group: "findings", | |
| 152 | title: "Code quality", | |
| 153 | status: "coming", | |
| 154 | about: "Maintainability and reliability findings beside the security ones. Not built yet.", | |
| 155 | action: null, | |
| 156 | }, | |
| 157 | ]; | |
| 158 | } | |
| 159 | ||
| 160 | /** The rows of one group, in order. */ | |
| 161 | export function rowsIn(rows: OverviewRow[], group: RowGroup): OverviewRow[] { | |
| 162 | return rows.filter((row) => row.group === group); | |
| 163 | } | |
| 164 | ||
| 165 | /** | |
| 166 | * The SECURITY.md "Set up a security policy" proposes: how to report, and | |
| 167 | * which versions are supported, for the maintainers to finish. | |
| 168 | */ | |
| 169 | export function securityPolicyTemplate(repo: string, reporting: boolean, base: string): string { | |
| 170 | const report = reporting | |
| 171 | ? `Report it privately at https://g1t.sh${base}/security/report. You can report without an account; leave an email address so the maintainers can answer you.` | |
| 172 | : `Email the maintainers (fill in the address here) rather than opening an issue, so the problem is not public before a fix is.`; | |
| 173 | return `# Security policy | |
| 174 | ||
| 175 | ## Reporting a vulnerability | |
| 176 | ||
| 177 | If you find a vulnerability in ${repo}, do not open an issue about it. | |
| 178 | ||
| 179 | ${report} | |
| 180 | ||
| 181 | Say what is affected, how to reproduce it and, if you can, how bad you think it is. We aim to answer within a few days and will keep you informed as we work on a fix. If you want to be credited in the advisory, say so. | |
| 182 | ||
| 183 | ## Supported versions | |
| 184 | ||
| 185 | | Version | Supported | | |
| 186 | | ------- | --------- | | |
| 187 | | latest | Yes | | |
| 188 | ||
| 189 | Fill in which releases get security fixes. | |
| 190 | `; | |
| 191 | } | |
| 192 | ||
| 193 | /** The pull request's body for the policy. */ | |
| 194 | export function securityPolicyPullBody(path: string): string { | |
| 195 | return `Adds \`${path}\`, which tells people how to report a vulnerability and which versions get security fixes. Edit the address and the versions before merging.`; | |
| 196 | } | |
| 197 | ||
| 198 | /** A branch name for the policy that is not taken. */ | |
| 199 | export function securityPolicyBranch(taken: string[]): string { | |
| 200 | let name = "add-security-policy"; | |
| 201 | for (let n = 2; taken.includes(name); n++) name = `add-security-policy-${n}`; | |
| 202 | return name; | |
| 203 | } |
This file's history is long; its oldest lines are credited to the oldest commit read.