Skip to content

Commit cbe6c42

Browse files
docs: OpenSSF Best Practices proposal — Silver plan, Scorecard fixes, Gold roadmap (#216)
* docs: propose OpenSSF Best Practices Silver plan and Scorecard fixes Audit of badge project 12651 against the current repo: Passing is 100% but every Silver/Gold/OSPS question is unanswered, and the badge entry still points at the pre-rename infobloxopen org URL, which is why Scorecard's CII-Best-Practices check reports 0 despite the badge. Sequence the work into four phases: badge URL fix, questionnaire pass over already-met criteria, small repo changes (roadmap, assurance case, coverage gate, signed tags), and Gold items gated on contributor growth. Signed-off-by: Ingmar Van Glabbeek <ivanglabbeek@infoblox.com> * docs: record maintainer decisions and Gold execution plan in OpenSSF proposal Interview outcomes: 1-approval review policy bound via enforce_admins, dedicated coverage push to 90/80, repro-build + Atheris + OSS-Fuzz all in scope, Infoblox internal security review, Gold-ready in 1-2 cycles. Verified same day: 0 org members lack 2FA (require-2FA is safe to flip), main already requires 1 review + 8 strict checks, and the uncovered- statement mass concentrates in cli/main.py and mcp/server.py (~41%). Signed-off-by: Ingmar Van Glabbeek <ivanglabbeek@infoblox.com> --------- Signed-off-by: Ingmar Van Glabbeek <ivanglabbeek@infoblox.com> Co-authored-by: Igor Racic <iracic82@gmail.com>
1 parent 31dcfaf commit cbe6c42

1 file changed

Lines changed: 250 additions & 0 deletions

File tree

Lines changed: 250 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,250 @@
1+
# Proposal: OpenSSF Best Practices — Silver badge, Scorecard fixes, and the road to Gold
2+
3+
- **Status:** Proposed (decisions on review policy, coverage pacing, fuzzing scope,
4+
security-review route, and timeline recorded 2026-07-29 — see §Decisions)
5+
- **Date:** 2026-07-29
6+
- **Scope:** [OpenSSF Best Practices badge](https://www.bestpractices.dev/projects/12651) (Silver/Gold levels), [OpenSSF Scorecard](https://scorecard.dev/viewer/?uri=github.com/dns-aid/dns-aid-core), and the OSPS Security Baseline questionnaire
7+
8+
## Summary
9+
10+
DNS-AID earned the **Passing** badge (100%) on 2026-04-25 and has not touched the
11+
badge entry since. The Silver questionnaire sits at 15% and Gold at 22% — almost
12+
entirely because the questions are **unanswered**, not because the practices are
13+
missing. An audit of the badge API against the current repository shows that the
14+
large majority of Silver criteria are already satisfied by existing files, CI
15+
workflows, and release automation; a handful need small, well-scoped changes.
16+
17+
Separately, the badge entry still points at the pre-rename
18+
`github.com/infobloxopen/dns-aid-core` URL, which is why OpenSSF Scorecard's
19+
`CII-Best-Practices` check scores **0/10** ("no effort to earn a badge detected")
20+
despite the achieved badge. Fixing that one URL raises the overall Scorecard
21+
score at zero engineering cost.
22+
23+
This proposal sequences the work into four phases: an immediate metadata fix,
24+
documentation PRs, CI/process hardening, and a Gold execution plan targeting
25+
**Gold-ready within 1–2 release cycles**, with `contributors_unassociated` as
26+
the sole criterion gated on ecosystem growth.
27+
28+
## Decisions (2026-07-29)
29+
30+
Recorded from maintainer review of the draft; facts verified against the GitHub
31+
API the same day.
32+
33+
| Topic | Decision / fact |
34+
| --- | --- |
35+
| Badge entry access | Held by @iracic82 only; questionnaire edits are coordinated with him (or he adds a co-owner login on the entry) |
36+
| Org admin | @ivanglabbeek is a dns-aid org owner — settings changes are direct actions, not requests |
37+
| Org 2FA status | **0 members have 2FA disabled** (verified via API) — `require_2FA` can be enforced with no member ejections |
38+
| Branch protection on `main` | Already requires 1 approving review with stale-review dismissal + 8 required status checks (strict). Gaps: `enforce_admins` off, last-push approval off |
39+
| Review policy | 1 approval on **all** PRs (already configured); add `enforce_admins` so it binds admins too |
40+
| Coverage pacing | **Dedicated push now** to 90% statement / 80% branch, not a slow ratchet |
41+
| Fuzzing & builds | All three: reproducible-build CI job, Atheris harness in CI, OSS-Fuzz application |
42+
| Security review | Infoblox internal security team (reviewers independent of the dev team), written report |
43+
| External contributors | Candidates in pipeline (IETF/ecosystem); tracked as the one open Gold blocker |
44+
| Timeline | Gold-ready in the next 1–2 release cycles |
45+
46+
## Current state
47+
48+
| Metric | Value | Source |
49+
| --- | --- | --- |
50+
| Best Practices — Passing | **100% (achieved 2026-04-25)** | bestpractices.dev project 12651 |
51+
| Best Practices — Silver | 15% (criteria unanswered) | same |
52+
| Best Practices — Gold | 22% (criteria unanswered) | same |
53+
| OSPS Security Baseline (tiered) | unanswered | same |
54+
| Scorecard (aggregate) | 8.0 / 10 | api.securityscorecards.dev |
55+
| Unit-test coverage | 79% combined statement+branch; ≈81% statement-only (measured 2026-07-29, 2142 tests) | local run of `tests/unit/` |
56+
57+
Scorecard checks below 10: `CII-Best-Practices` 0, `Fuzzing` 0, `Code-Review` 2,
58+
`Branch-Protection` 4, `Pinned-Dependencies` 8, `Signed-Releases` 8,
59+
`Token-Permissions` 9.
60+
61+
## Phase 0 — Immediate metadata fix (no code)
62+
63+
1. **Update the badge entry URLs.** The bestpractices.dev entry's `repo_url` and
64+
`homepage_url` still read `https://github.com/infobloxopen/dns-aid-core`.
65+
Update both to `https://github.com/dns-aid/dns-aid-core` (badge-entry owner
66+
action; bestpractices.dev supports repo URL changes with a rename note).
67+
This alone should move Scorecard `CII-Best-Practices` from 0 to 5 (passing
68+
badge detected), and to 7 once Silver is achieved.
69+
70+
## Phase 1 — Silver: answer what is already true
71+
72+
These criteria are already satisfied; the work is filling in the questionnaire
73+
with evidence links. No repository changes required.
74+
75+
| Criterion | Evidence already in the repo |
76+
| --- | --- |
77+
| `dco` | [DCO](../../DCO) file; `dco.yml` workflow enforces sign-off on every PR |
78+
| `governance` | [GOVERNANCE.md](../../GOVERNANCE.md) (roles, lazy consensus, voting) |
79+
| `code_of_conduct` | [CODE_OF_CONDUCT.md](../../CODE_OF_CONDUCT.md) |
80+
| `roles_responsibilities` | GOVERNANCE.md §Roles; [MAINTAINERS.md](../../MAINTAINERS.md) role table |
81+
| `bus_factor` | Three maintainers listed in MAINTAINERS.md (≥2 required) |
82+
| `documentation_architecture` | [docs/architecture.md](../architecture.md) |
83+
| `documentation_quick_start` | [docs/getting-started.md](../getting-started.md) |
84+
| `documentation_current` | Docs updated in lockstep with releases (CHANGELOG discipline) |
85+
| `documentation_achievements` | Badge row in README |
86+
| `coding_standards` / `coding_standards_enforced` | CONTRIBUTING.md; ruff + mypy jobs are required CI |
87+
| `maintenance_or_update` | SECURITY.md supported-versions table; SUPPORT.md |
88+
| `vulnerability_response_process` | SECURITY.md response timeline (48h / 7d / 30d) |
89+
| `external_dependencies` | pyproject.toml + uv.lock enumerate all dependencies |
90+
| `dependency_monitoring` | Dependabot + nightly `pip-audit` in security.yml |
91+
| `updateable_reused_components` | All deps from PyPI, floor-pinned, lockfile-managed |
92+
| `interfaces_current` | [docs/api-reference.md](../api-reference.md) |
93+
| `automated_integration_testing` | `integration` job in ci.yml (mock integration suite) |
94+
| `regression_tests_added50` | Bug-fix PRs ship regression tests (see recent history, e.g. #201) |
95+
| `test_policy_mandated` | CONTRIBUTING.md "Tests (required)" checklist |
96+
| `installation_common` / `installation_development_quick` | `pip install dns-aid`; CONTRIBUTING dev setup |
97+
| `signed_releases` | Sigstore/cosign signatures (`.sig`/`.pem`) on every release artifact + SBOM |
98+
| `implement_secure_design` / `input_validation` | SECURITY.md (SSRF protections, input validation rules, cap-sha256 integrity) |
99+
| `crypto_*` (agility, certificate verification, TLS ≥1.2, network crypto) | httpx/TLS defaults; DANE/TLSA and DNSSEC handling documented in SECURITY.md |
100+
| `hardening` | SSRF allowlist-deny-by-default, HTTPS-only fetches, localhost-bound MCP transport |
101+
| `build_*` (repeatable, non-recursive, standard variables) | hatchling + uv.lock; pure-Python build (several N/A with justification) |
102+
| `accessibility_best_practices`, `internationalization`, `sites_password_security` | N/A with justification (library/CLI; no UI, no password-accepting site) |
103+
104+
## Phase 2 — Silver: small, concrete repo changes
105+
106+
Each item below is a small PR; together they close every remaining Silver MUST.
107+
108+
1. **`documentation_roadmap` — add `docs/roadmap.md`.** The only Silver MUST with
109+
no existing artifact. One page: near-term (IETF draft tracking, backend
110+
parity), mid-term (LF onboarding goals from MAINTAINERS.md), and a pointer to
111+
the issue tracker as the source of truth. Link it from README.
112+
113+
2. **`vulnerability_report_credit` — one paragraph in SECURITY.md** committing to
114+
credit reporters in release notes/advisories unless they request anonymity
115+
(the practice already happens; it just isn't written down).
116+
117+
3. **`assurance_case` — add `docs/security/assurance-case.md`.** A structured
118+
argument mapping threats → mitigations. Most content already exists in
119+
SECURITY.md (SSRF, DNSSEC/AD-flag trust model, DANE modes, cap-sha256
120+
integrity, input validation) and docs/rfc/security-considerations.md; this
121+
document arranges it as claim → argument → evidence, adds a trust-boundary
122+
diagram, and states what is explicitly out of scope (resolver compromise).
123+
124+
4. **`test_statement_coverage80` — enforce coverage in CI.** Coverage is already
125+
measured but not gated, and the criterion is already met on the measure it
126+
uses: statement-only coverage is ≈81% (the 79% figure in CI reports includes
127+
branch coverage, which is stricter). Add `--cov-fail-under=79` to the ci.yml
128+
coverage step immediately so the achieved level cannot regress while the
129+
Gold coverage push (G3 below) is underway; the gate rises with the push and
130+
is never lowered without a recorded decision.
131+
132+
5. **`version_tags_signed` — sign release tags.** Release *artifacts* are already
133+
Sigstore-signed; the git tags themselves are not. Update RELEASE.md to require
134+
`git tag -s` (maintainer GPG/SSH key) or gitsign for `v*` tags.
135+
136+
6. **`access_continuity` — one paragraph in GOVERNANCE.md** documenting that at
137+
least two people hold org-owner/admin access and that the Project Lead role
138+
has a succession process (currently only implied by the election clause).
139+
140+
## Phase 3 — Scorecard hardening (parallel to Phase 2)
141+
142+
These raise the Scorecard score and simultaneously pre-answer Gold and OSPS
143+
Baseline questions:
144+
145+
1. **Branch protection (currently 4/10) + Code-Review (currently 2/10).**
146+
Verified 2026-07-29: `main` already requires 1 approving review with
147+
stale-review dismissal and 8 strict status checks. The remaining gaps are
148+
`enforce_admins` (off — admins can currently merge without review, which is
149+
also why the Code-Review score is low: 5/21 recent changesets carried
150+
approvals) and optionally require-last-push-approval. Action: enable
151+
`enforce_admins`; the Code-Review score then recovers on its own as the
152+
trailing 30-changeset window fills with reviewed merges.
153+
2. **Token-Permissions (9/10).** Audit workflows for job-level `permissions`
154+
blocks (likely one workflow missing an explicit top-level `permissions:
155+
contents: read`).
156+
3. **Fuzzing (0/10).** Two tracks (decided): a small
157+
[Atheris](https://github.com/google/atheris) harness fuzzing the SVCB
158+
wire-format parser and record deserializers (the highest-value
159+
untrusted-input surface) on a weekly CI schedule, **and** an OSS-Fuzz
160+
application once the harness runs clean for a couple of weeks (needs a
161+
maintainer contact email and an `oss-fuzz` project directory PR).
162+
4. **Pinned-Dependencies (8/10).** Workflows already pin actions by SHA; the
163+
residual findings are `pip install` steps in release.yml — pin
164+
`build`/`cyclonedx-bom` versions with hashes.
165+
166+
## Phase 4 — Gold execution plan
167+
168+
Target: **Gold-ready within 1–2 release cycles**, meaning every Gold criterion
169+
is Met except `contributors_unassociated`, which is tracked as the single open
170+
blocker and worked via the contributor pipeline.
171+
172+
Already met — answer on the form with evidence, no work:
173+
174+
- `copyright_per_file` / `license_per_file` — all 86 source files carry SPDX +
175+
copyright headers.
176+
- `repo_distributed`, `test_invocation`, `test_continuous_integration` — carried
177+
over from Passing.
178+
- `crypto_used_network` / `crypto_tls12` / `hardened_site` / `hardening`
179+
HTTPS-only fetches (TLS ≥1.2 via httpx defaults), GitHub-hosted site with
180+
HSTS, SSRF/input-validation hardening per SECURITY.md.
181+
- `dynamic_analysis` — already answered Met at Passing.
182+
183+
Work items:
184+
185+
- **G1 — Org settings (owner: @ivanglabbeek, immediate).** Enable "Require
186+
two-factor authentication" on the dns-aid org (`require_2FA`; verified safe —
187+
0 members lack 2FA, so nobody gets ejected). GitHub requires TOTP/security
188+
keys rather than SMS-only for org enforcement, covering `secure_2FA`. Enable
189+
`enforce_admins` on main's branch protection (see Phase 3.1).
190+
- **G2 — Review standards (1 small PR).** Add a "Code review" section to
191+
CONTRIBUTING.md: what reviewers check (correctness, tests, security-sensitive
192+
paths, DCO), who may approve, and the rule that no change merges without a
193+
non-author approval (`code_review_standards`). `two_person_review` (≥50% of
194+
changes reviewed by a non-author) is then enforced mechanically by G1 +
195+
existing branch protection; the criterion evaluates recent history, so it
196+
becomes claimable roughly one release cycle after enforcement.
197+
- **G3 — Coverage push (the main engineering item, this cycle).** Dedicated
198+
test-writing effort to reach 90% statement / 80% branch (currently ≈81%
199+
statement). The gap is concentrated: `cli/main.py` (443 uncovered statements,
200+
50%) and `mcp/server.py` (394, 30%) hold ~41% of all uncovered statements,
201+
followed by `backends/infoblox/bloxone.py` (137, 53%), `core/invoke.py`
202+
(103, 55%), `backends/infoblox/nios.py` (102, 70%), and
203+
`backends/cloud_dns.py` (65, 53%). Approach: typer `CliRunner` tests for the
204+
CLI command surface, MCP tool-handler tests against the mock backend, and
205+
mocked-HTTP tests for the two Infoblox backends and Cloud DNS (the
206+
`test_cloudflare_backend.py` pattern already exists). Raise the
207+
`--cov-fail-under` gate as each tranche lands.
208+
- **G4 — Reproducible builds (1 PR).** CI job that builds the wheel/sdist twice
209+
with `SOURCE_DATE_EPOCH` pinned and fails on binary diff
210+
(`build_reproducible`; hatchling is reproducible by default, so this is
211+
expected to pass immediately and serve as the criterion's evidence URL).
212+
- **G5 — Fuzzing (1 PR + application).** Atheris harness in weekly CI, then the
213+
OSS-Fuzz application (Phase 3.3). Not a Gold criterion, but scheduled here
214+
because the harness reuses G3's test fixtures.
215+
- **G6 — Security review (owner: @ivanglabbeek, external ask).** Request a
216+
review from the Infoblox product-security team — reviewers must be
217+
independent of the dev team for `security_review` to count. Scope: the
218+
assurance case (Phase 2.3), SSRF/input-validation paths, DNSSEC/DANE trust
219+
handling, and release pipeline. Deliverable: a written report linked from
220+
SECURITY.md, with findings triaged as issues.
221+
- **G7 — Starter tasks (ongoing).** Label `good first issue` tasks
222+
(`small_tasks`) — also feeds the contributor pipeline that G8 depends on.
223+
- **G8 — Unassociated contributors (open blocker).** Candidates exist in the
224+
pipeline (IETF draft co-authors, ARD-ecosystem developers). The criterion
225+
needs two *significant* contributors not associated with Infoblox — track
226+
candidate progress in the LF-graduation issue and revisit at each release.
227+
Everything else in this plan proceeds independently.
228+
229+
## OSPS Security Baseline
230+
231+
The badge entry also carries the OSPS Baseline questionnaire (`OSPS-*` criteria,
232+
all unanswered). Nearly every control maps to evidence produced by Phases 0–3
233+
(MFA, branch protection, SAST, dependency policy, release signing, vuln
234+
process). Fill it in **after** Phase 3 lands so the answers are all "Met" on
235+
first submission.
236+
237+
## Sequencing and ownership
238+
239+
| When | Items | Owner |
240+
| --- | --- | --- |
241+
| Now (settings, no PR) | G1: org require-2FA, `enforce_admins`; Phase 0 badge-URL fix | @ivanglabbeek; @iracic82 for the badge entry |
242+
| Release cycle 1 | Phase 2 PRs (roadmap, assurance case, SECURITY/GOVERNANCE paragraphs, `--cov-fail-under=79`, signed tags); G2 review standards; G4 repro-build job; Phase 3 token-perms + pip pins; Silver questionnaire pass | maintainers; @iracic82 for the questionnaire |
243+
| Release cycle 1–2 | G3 coverage push to 90/80 (CLI → MCP server → Infoblox/Cloud DNS backends); G5 fuzz harness + OSS-Fuzz application; G6 security review request → report | maintainers; Infoblox security team for G6 |
244+
| After cycle 2 | Claim `two_person_review` (needs a cycle of enforced history); Gold questionnaire pass; OSPS Baseline pass | @iracic82 (form), maintainers (evidence) |
245+
| Unscheduled | G8 `contributors_unassociated` — pipeline candidates tracked per release | project lead |
246+
247+
Silver is achievable within release cycle 1. Every Gold criterion except
248+
`contributors_unassociated` is scheduled above; that criterion aligns exactly
249+
with the existing LF-graduation recruiting goals in MAINTAINERS.md, so no new
250+
organizational commitments are introduced by this proposal.

0 commit comments

Comments
 (0)