Skip to content

Trace one service from source to runtime

Produce an application inventory that joins repository revisions, artifact digests, deployments and owners. Keep missing relationships visible before counting scanner findings.

30 MIN

By AISecurityInterviews · Updated

TL;DR: A repair can be closed only for the deployments it actually reaches. Build the source-to-runtime map before assigning findings or measuring completion.

Where you are. You are starting the application-security course by establishing the objects every later assessment must refer to.

Build the inventory from records you can join

Use the fictional document service as a small part of a large customer platform. Its components have different release cadences: the API runs continuously, the conversion worker scales with demand, and the importer may remain idle between monthly jobs. An inventory based only on currently running processes will miss configured future execution.

ComponentSourceArtifact observationDeployment observation
APIweb at R2Build b12 produced A2East production runs A2
Workerdocument at R2Tag stable, digest unresolvedWest production references stable
Importerdocument at R1Build b08 produced D1Schedule still selects D1

R1, R2, A2, D1 and D2 are symbolic exercise identifiers, not actual hashes. In real records, store the digest algorithm and full value. The current checkout is not necessarily the source of deployed bytes, and the current value of a mutable tag is not historical proof of what ran.

Start with the release packet

The fictional service has two repositories. The web repository produces a frontend and an API. The document repository produces a conversion worker and a monthly importer. Both repositories use a shared parser package. The API team owns application code, while the platform team owns the base image and production deployment.

Your first deliverable is an inventory with one row per deployed component. Include repository revision, build run, artifact digest, environment, service owner and business purpose. Do not combine the frontend and API simply because they share a repository. Their data and permissions can differ.

Preserve missing joins

The frontend has a verified build record. The worker has only a mutable image tag. The importer has not run this month, but its scheduled template still references an older digest. Record the worker's artifact relationship as unresolved and the importer's configured artifact separately from its last execution.

This distinction changes security work. A source patch may already be available while the importer still schedules vulnerable bytes. A quiet runtime view may simply mean the importer did not execute during the observation period. Neither condition supports closing its dependency finding.

Give each relationship an owner

The repository owner can explain the source and dependency graph. The build owner can provide provenance and artifact identity. The service owner can confirm the production rollout and operational impact. Assign responsibility for obtaining missing evidence rather than asking one team to certify facts it does not control.

Avoid treating an ownership tag as permanent truth. A team rename, service transfer or acquisition can leave tags stale. Record how ownership was confirmed and who accepts the repair deadline. A security platform can suggest an owner, but a real handoff needs acknowledgment.

Review the inventory as a security boundary

The map also exposes authority. The monthly importer reads customer documents, while the frontend does not. A shared parser issue can therefore have different consequences across components. Keep those differences visible when grouping a common repair.

Only include identifiers needed for the exercise. An inventory should not store live credentials or raw customer documents. Restrict access to detailed production relationships when they reveal sensitive infrastructure. The course uses fictional records so the review can be performed entirely offline.

SECURITY OPERATIONS
Follow one component across ownership boundaries
1/4

Repository

Revision and code owner

One repository can produce several separately affected services.

Model assertions, not just asset rows

The evidence graph has several kinds of edge: source revision built into an artifact, artifact selected by a deployment, deployment observed on a workload, and a team accepting ownership. Each edge needs its own observer and timestamp. A build system can attest what it produced without knowing whether every production region installed it. Qualify revisions by repository: web at R2 and document at R2 are different source subjects. A2 is the API artifact; D1 and D2 are document-worker artifacts.

Preserve both desired and observed deployment state. During a rolling update, the configured digest may be D2 while some instances still run D1. For a scheduled job, retain the template's selected digest as well as the last completed run. Otherwise “no affected running instance” can hide an affected task that starts tomorrow.

builds = [
    {"builder": "release-builder", "run": "b12", "repository": "web", "revision": "R2", "digest": "A2"},
    {"builder": "release-builder", "run": "b08", "repository": "document", "revision": "R1", "digest": "D1"},
]
assets = [
    {"name": "api-east", "kind": "running", "repository": "web", "digest": "A2"},
    {"name": "worker-west", "kind": "running", "repository": "document", "digest": None, "tag": "stable"},
    {"name": "monthly-importer", "kind": "scheduled", "repository": "document", "digest": "D1"},
]
# These claims are prevalidated exercise inputs, not unverified attestations.
by_digest = {}
for build in builds:
    by_digest.setdefault(build["digest"], []).append(build)

def classify(asset):
    candidates = by_digest.get(asset["digest"], [])
    if len(candidates) != 1 or candidates[0]["repository"] != asset["repository"]:
        return "unresolved"
    return "current" if candidates[0]["revision"] == "R2" else "prior-revision"

result = {asset["name"]: classify(asset) for asset in assets}
assert result == {"api-east": "current", "worker-west": "unresolved", "monthly-importer": "prior-revision"}
# A conflicting second claim requires review rather than last-write-wins.
by_digest["A2"].append({"repository": "web", "revision": "R1", "digest": "A2"})
assert classify(assets[0]) == "unresolved"
print(result["api-east"], result["worker-west"], result["monthly-importer"])  # => current unresolved prior-revision

This conservative example requires one unambiguous claim. Multiple legitimate builds can produce the same bytes, so a real verifier should evaluate claim consistency and trusted producers rather than rejecting every duplicate. The important failure mode is selecting whichever claim arrived last when trusted claims disagree about relevant inputs.

A signature authenticates a statement under a key or identity; it does not establish that the builder was uncompromised or that the statement describes the required build process. Verification must bind the subject digest, expected builder, source inputs and permitted build configuration. Keep the trust policy version alongside the attestation so a later policy change can trigger reevaluation.

Diagram
Verify each edge independently
1/4

Source

Reviewed revision and dependencies

An attested artifact and a completed deployment are different claims.

Make the graph useful for remediation

Suppose one parser dependency is affected. Identify every component containing that dependency, then join to reachable deployments and scheduled templates. A monorepo label is too coarse: the frontend and importer may share source ownership but not a dependency, data class or runtime permission.

Use explicit relationship states such as confirmed, conflicting and absent. “Absent” means the relationship is not known, not that the component is unaffected. Assign an evidence owner to unresolved edges. The build team resolves the worker's digest; the platform team checks the scheduled importer; the application owner confirms which parser paths accept customer documents.

Keep a stable service identity through team renames and acquisitions. Ownership tags are useful discovery hints, but closure requires someone to accept the service and its remediation scope. Store that acceptance with a date. An orphaned deployment should remain in the denominator until its retirement is verified, not disappear because its team no longer exists.

Finally, define the snapshot's boundary: accounts, regions, clusters and collection time. “Three of three components reviewed” is meaningful for this fixture, but cannot describe the enterprise until the inventory boundary is established. Retain unknown assets and failed collectors alongside the graph so a platform outage does not improve the apparent repair rate.

Diagram
A quiet job can still select affected bytes

Runtime-only view

No running importer

Remove it from inventory

Next schedule

Old digest executes

Outcome, unsafe: Future exposure omitted

Configured execution view

Template D1

Keep scheduled artifact in scope

Repair D2

Verify template and next run

Outcome, safe: Closure includes future execution

1/2

Runtime-only view

Future exposure omitted

Include configured workloads even when they are not currently active.

Do this before moving on

Run the inventory program and add a second running API instance on an older API artifact A1. Produce one row per running instance or scheduled template, including desired digest, observed digest, source relationship, owner and evidence time. Leave the worker unresolved until a trusted runtime digest is supplied.

Write the closure request for the parser repair. It must include the old API instance and the monthly importer. Explain what evidence proves each has stopped selecting D1, and which team can provide that evidence.

Review your result. A passing inventory does not resolve a historical artifact through today's tag value. It retains idle configured work, handles conflicting claims explicitly and separates build evidence from deployment evidence. Each unknown edge has a named evidence owner and a next action.

Go deeper

  • ASPM explains the application graph and why finding counts can mislead.
  • SBOMs distinguishes inventory content from proof of deployed behavior.
  • Verify an ASPM repair adds rollback and multiple-owner constraints to this inventory review.

Key takeaways

  • Inventory deployed components rather than only repositories.
  • Keep configured state separate from observed execution.
  • Assign evidence requests to the owner who can answer them.

Check yourself

Say or write your answer first, then reveal. Explaining it from memory, in your own words, is the skill an interviewer is checking.

  1. 1Why keep desired and observed artifact identities?

  2. 2Does a valid attestation signature prove a safe build?

  3. 3How should two conflicting source claims for one digest be handled?

  4. 4Why does an idle importer remain in scope?

Sign in to track which lessons you have finished.