Your Application Security Budget Was Set Before Anyone Counted the Repositories
The number in your application portfolio and the number of places your code lives are two different numbers. Coverage metrics, tiering, and staffing models all rest on the second one. The budget gets set first, and the counting happens after it.
The number underneath the portfolio
Your application portfolio has a number in it. It came from a CMDB entry that was accurate the day someone wrote it, or from the memory of whoever has been there longest. It answers a different question from the one an application security program has to answer.
An application is a thing the business names and funds. A repository is a thing a scanner runs against, a pipeline builds, and a person has to own. A product assembled from a web front end, three backend services, and a shared library is one row in the portfolio and five places where the work lands. Both views are accurate. Only one of them can be staffed.
The second number goes missing for structural reasons. Each of the items below is a local decision that made sense to the person who took it.
- An acquisition arrives with its own source control tenant and stays live, because the migration was deprioritized twice
- A GitLab instance predates the move to GitHub and still hosts build tooling nobody wants to touch
- Contractor organizations outlive the program they were stood up for
- Forks, mirrors, and template repositories accumulate
- Archived repositories stay in the tenant, since deletion is a task somebody has to be assigned before it happens
The inventory is work with a deliverable of its own
The gap surfaces after the budget is approved, and it surfaces quietly. The program then runs at a different size from the one it was planned at.
The instinct is to fold discovery into the first phase of a tool rollout, or hand it to whoever on the platform team has a spare fortnight. That produces a survey: one call with the head of platform engineering, a screenshot of the organization list, a count from whoever answered fastest. Six months later, when somebody asks why a system was out of scope, the answer has to be reconstructed from memory.
Treat the inventory as bounded work instead. A fixed duration, a named deliverable, a named owner, and an acceptance step where someone with authority confirms the tenant list is complete. Whether your own engineers run it or you bring in help is a capacity question. A completion date is what turns it into funded work.
Sizing follows from it. CWS scopes application security engagements in tiers by estate size, and which tier applies is an output of discovery. On the one estate CWS has counted end to end, that number came to roughly 6,300 repositories.
A program plan built before the inventory exists is a guess with a budget attached.
What the inventory records: ownership, activity, exposure, build path
A count on its own gives you one bigger number. Each row needs four fields beyond its identity before it can carry a decision.
Ownership means a named person and a team, not a group mailbox. Record how it was determined as well as who holds it: an owner from a CODEOWNERS file enforced on merge is a different answer than one inferred from the last commit. Findings routed to an unowned repository sit in the queue until somebody adopts them.
Activity separates live from dormant from abandoned. Archived repositories that were left in place inflate the count, and they are the cheapest rows to take back out once the data is on the table.
Exposure promotes a repository regardless of how busy it looks. The under-rated category is the shared library. A wide dependency footprint carries more blast radius than an active marketing site, and a ranking that runs on commit volume puts it near the bottom.
Build path decides whether a repository can be onboarded at all. Gating one that has no pipeline requires engineering work first, and somebody pays for that work whether or not it appears in the plan.
Record unknown as a value. A blank cell reads as zero to whoever builds the estimate, and it does that silently. An explicit unknown lands on the gap list.
- Identity means the tenant, organization, repository name, visibility, and archived flag
- Ownership needs a named person, their team, and a record of how that ownership was determined
- Activity is the last commit, commit frequency over a trailing window, and branch count
- Exposure asks whether it faces the internet, whether regulated data or a payment path runs through it, whether customers install it, and how wide the dependency footprint reaches
- Build path covers the CI system, whether a pipeline exists, artifact type, language, and package manager, since software composition coverage varies by ecosystem
From 6,300 repositories to a top tier you can defend
Year one funds a subset. The inventory is there to produce a shortlist that survives the engineering director who asks why their repository was left out, and the audit committee that asks in month six what the criteria were.
The remainder becomes the roadmap, already enumerated and already carrying owners and exposure ratings. Year two turns into a decision about what to bring in next, taken against data your engineering leaders have seen. Getting to a shortlist that holds runs in a fixed order.
- Rank by exposure and blast radius first. Size and the date of the last commit are the axes that mislead
- Filter on activity second, and only where activity and exposure agree. A repository that is dormant and also undeployed and unimported is a records management item. One that has stopped receiving commits while still serving traffic or sitting in other teams' dependency trees stays in scope
- Check the ranking against ownership. A repository that clears the exposure filter with no owner needs one before phase one, and assigning it is a governance task measured in weeks that has to run inside your organization
- Write the thresholds down with the date and the name of whoever set them
What to write down before you commit to a number
Separate the two commitments. The inventory is fixed work against a fixed deliverable and a fixed date, and it can be committed to now. Scope and budget depend on what it finds. If the cycle demands a figure first, give a band and name the inventory as the event that fixes it.
An assumption recorded is a position you can stand on when the real number arrives. The same assumption unlabeled in a spreadsheet is a variance you will be asked to explain. A scope dispute is a definition dispute in costume. Both readings were available when the work was scoped, so the one that went unwritten becomes the one the other party remembers.
- Write the assumption down and label it as one. Planning assumes approximately this many repositories across this many tenants, as stated by this role on this date
- Settle the unit of work. A monorepo of forty services counts as one repository or as forty, and forks, mirrors, and archived repositories each get a stated treatment
- Put the re-baseline trigger in as a percentage. If the validated count exceeds the assumption by more than that figure, the plan gets rebuilt before the next phase
- Pin down access. Read access to every tenant, a named contact per tenant, and a date by which credentials are provisioned. An inventory waiting on credentials is an inventory that has stopped
- Get acceptance in writing. A named person confirms the tenant list is complete to the best of their knowledge, so a fourth instance found in month five is handled as a scope adjustment against a written baseline
A trigger written as a materially larger estate just schedules the disagreement for later.
What the readout hands to strategy
Hand the inventory over as data you can re-run. A queryable table with its collection method documented alongside it can be diffed against next quarter and handed to a vendor as the basis for a scoping conversation, which turns the annual re-baseline into small work. A slide deck has to be rebuilt from scratch each time.
Tool selection then becomes arithmetic. Ecosystem coverage gets checked against the languages the estate contains, and licensing gets sized on the unit each product meters, which for application security scanners is the contributing developer count or the volume of code. The repository count is what sets the coverage denominator and the tiering. Staffing becomes triage hours derived from your own active repository count and observed findings density, not a ratio borrowed from an organization with a different estate. Governance gets a denominator.
The NIST Secure Software Development Framework opens with organizational preparation. OWASP SAMM opens with Governance, and its usage guidance starts with an assessment of current practice. Both take the count as given. Threshold ownership, and what to fix in writing before committing to a number, are CWS recommendations. The frameworks assume the count already exists, and producing it is field work. It is also the step that makes every number after it defensible. Besides the table, the readout carries five things.
- A tenant map showing every source control instance and what access exists today
- The tiering, with criteria written out and thresholds attributed to whoever approved them
- A gap list, one row per repository still missing an owner, a pipeline, or a determinable exposure
- A phased scope stating what phase one covers, what is deferred, and on which criterion each deferral rests
- Pipeline work as its own scope item with a cost and an owner. Left off the list, it lands on whoever is closest to the deadline, and the phase absorbs the overrun
The findings held because somebody counted first.