A team of one cannot do everything, so the useful question is what to do first and how to tell whether it is working. This plan assumes one security engineer, a few dozen repositories, a CI system and at least one cloud account. It works the line roughly in the order code travels through it.
Each block is two weeks. The rule for every block is the same: finish with a control that runs everywhere, even if it is basic, rather than a perfect control on a single pilot repository.
Weeks 1-2: inventory the line
You cannot secure what you have not listed. Build a plain inventory of repositories, owners, languages, pipelines, deploy targets and who holds admin rights. A spreadsheet is fine. Most of it can be pulled from the source control API.
# list repositories with their default branch and archive status
gh repo list your-org --limit 500 \
--json name,defaultBranchRef,isArchived,visibility \
--jq '.[] | [.name, .defaultBranchRef.name, .isArchived, .visibility] | @tsv'
Mark every repository with an owning team. Repositories without an owner are the first finding of the program.
Weeks 3-6: build and release stations
Two blocks on the part of the line where code is written and packaged.
- Branch protection and review. Require pull requests and at least one review on default branches. Turn on secret scanning and push protection where your platform supports it.
- Secrets in CI. Add Gitleaks as a non-blocking job everywhere, then make it blocking once the backlog is cleared.
- Dependencies. Generate an SBOM with Syft and scan it with Grype or Trivy. Start by reporting only, so teams see the shape of the problem before anything fails.
- Pipeline hygiene. Pin third-party actions to commit SHAs and set default workflow token permissions to read-only. Run actionlint and zizmor to catch the obvious mistakes.
# a minimal shared job, called from each repository
name: security-baseline
on: [pull_request]
permissions:
contents: read
jobs:
secrets:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@<pinned-sha>
with:
fetch-depth: 0
- run: gitleaks git --redact --exit-code 1 .
Weeks 7-10: run and design stations
Move to the two ends of the line that a lone engineer often skips.
- Run. Confirm that production logs from authentication, admin actions and the cloud control plane land somewhere searchable and are kept long enough to investigate. Write down who gets paged for a suspected incident.
- Design. Pick the two or three services that handle money, credentials or personal data and run a short STRIDE session with each team. One hour per service is enough to produce a list of risks and owners.
- Access. Review who holds admin in source control, CI and the cloud. Remove what is not needed and record the rest.
Weeks 11-13: the program around it
The last block turns activity into a program people can rely on.
- Triage rotaFindings land in one queue, with a named person each week and severity rules written down.
- Fix targetsAgree with engineering leadership how quickly each severity should be fixed, and what an exception looks like.
- ChampionsOne interested engineer per team who gets early notice of changes and a direct line to security.
- RoadmapA one-page plan for the next two quarters, based on what the first 10 weeks showed.
What to measure
Finding counts on their own are noise: they go up when you add a scanner and down when you switch one off. Measure a small set of things you can define precisely and that move when the program improves.
| Measure | Definition | Why it matters |
|---|---|---|
| Control coverage | Share of active repositories with branch protection, secret scanning and dependency scanning all enabled | Tells you whether the baseline is actually everywhere |
| Time to triage | Median time from a finding being raised to a person accepting, rejecting or assigning it | Shows whether the queue is alive or a graveyard |
| Time to fix | Median time from triage to closure, split by severity | The number leadership cares about, and the one that reflects engineering capacity |
| Recurrence | Share of closed findings whose rule fires again in the same repository within 90 days | Separates real fixes from suppressions and one-off patches |
Report these monthly on one page, as trends, alongside a short note on what changed. If you need a fifth measure, make it the number of services with a current threat model.
What to do on Monday
- Export your repository list and add an owner column.
- Pick one control from weeks 3-6 and roll it out in report-only mode to every repository this week.
- Book three one-hour design sessions for the services that matter most.
- Write the four measure definitions above into your team wiki, so the first report uses the same words as the last.
Where this sits on the line
In the tower (in development):