The deployment path is defined by configuration committed to the repo
Why it matters
SOC 2 CC8.1 requires that changes to infrastructure and software reach production through an authorized, repeatable path, and the first thing an auditor traces in the change-management section is "show me how a merged change becomes a deploy." This is an evidence-pointer check: it verifies committed evidence of the deployment path (a CI deploy job, a platform config file like vercel.json, a Dockerfile with orchestration, or IaC), which is what an auditor will ask for. It does not claim to see dashboard state. AI-built and vibe-coded apps fail this by construction: the standard flow is clicking "import repo" in the Vercel or Netlify dashboard, after which the platform deploys every push while the repo itself carries zero record of how production comes to exist. The deploy works, but when an auditor, a new engineer, or an incident review asks "what config governs this deploy," the answer lives only in a dashboard nobody can diff, review, or roll back through git. Committing the config file the platform already supports turns an invisible deploy path into reviewable, versioned evidence.
Severity rationale
Low because platform git integration (a Vercel or Netlify dashboard connected to the repo) is a legitimate, controlled deploy path that is invisible from the repo, so a fail here usually means missing committed evidence of the path rather than an actually ad hoc deployment.
Remediation
Commit the configuration your platform already honors: a minimal vercel.json at the repo root for Vercel, netlify.toml for Netlify, fly.toml for Fly, or a deploy job in .github/workflows/deploy.yml that runs your platform CLI. Even a minimal file pins the deploy path in git:
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"framework": "nextjs"
}
If you ship containers, commit the compose file or Kubernetes manifest beside the Dockerfile so the image has a committed path to production. The platform's git integration keeps doing the actual deploying; the committed file is the CC8.1 evidence an auditor traces when asking how a merged change ships.
Detection
- ID:
deployment-config-in-repo - Severity:
low - What to look for: This is an evidence-pointer check: it measures whether the deployment path is defined by files committed to the repo, not whether deploys succeed. Enumerate four evidence classes. (1) CI deploy:
.github/workflows/*.ymljobs or steps invokingvercel deploy/vercel --prod,netlify deploy,flyctl deploy/fly deploy,gcloud run deploy/gcloud app deploy,eb deploy,aws ecs update-service,kubectl apply,helm upgrade,actions/deploy-pages, or adocker pushfollowed by a deploy command;.gitlab-ci.ymlwith adeploystage; deploy jobs inJenkinsfileor.circleci/config.yml. (2) Platform config at the repo root:vercel.json,netlify.toml,fly.toml,render.yaml,app.yaml(Google App Engine),amplify.yml,railway.toml/railway.json,apprunner.yaml,Procfile(Heroku-style). (3) Container path:DockerfilePLUS at least one orchestration manifest referencing the app image (docker-compose.yml/compose.yaml,k8s/**/*.yamlorkubernetes/**/*.yaml, HelmChart.yaml). (4) IaC deploy resources:*.tfdeclaring resources the app runs on (aws_ecs_service,google_cloud_run_service,vercel_project),serverless.yml,sst.config.ts, a Pulumi program, or a CDK app. These file surfaces are language-independent: Django, FastAPI, Flask, and Go HTTP servers use the same platform configs, workflows, and manifests, so do not mis-skip a non-JS repo just becausepackage.jsonis absent. Separately, establish deployability for the fail branch: a framework app (next,nuxt,remix,@sveltejs/kit,astroin dependencies; anexpress/fastify/koaserver entrypoint; Djangomanage.py/wsgi.py; a FastAPI or Flask app module; a Gomain.gostarting an HTTP server) with production markers (abuildscript,.env.productionorNODE_ENV === 'production'references, or a README describing a live URL). For every candidate artifact, open it and quote the deploy step, config key, or resource block — never credit a filename you did not read. - Pass criteria: Any ONE evidence class is present and real: (a) a CI workflow containing an actual deploy step (a command or action that pushes to a hosting target, not just build/test), (b) a platform config file from the list at the repo root that is valid for its platform (a minimal
vercel.jsoncounts: its presence pins the platform in git), (c)Dockerfileplus at least one orchestration manifest referencing the app image, or (d) IaC files declaring the resources the app runs on. Do NOT pass on a filename alone: an.example/.templatefile, an empty or placeholder-filled config, or a workflow whose deploy step is commented out or gated behindif: falsedoes not count as pass. - Fail criteria: The repo is a deployable production app and none of the four evidence classes exists. Fail the sneaky variants too: CI workflows that only lint, test, and build with no deploy step; a deploy job that is commented out or gated behind
if: false; apackage.json"deploy"script that is anechostub or TODO; aDockerfilewith no orchestration manifest and no platform config anywhere (the image is defined but its path to production is not); a platform config that is an unadopted template (.example/.templatesuffix) or contains unfilled placeholders like{{PROJECT_NAME}}. - Skip (N/A) when: The repo is a library, CLI, or published package that is not deployed:
package.jsonhas abinfield or publishing markers (filesplusmain/exports) with no web framework dependency and no server entrypoint; or apyproject.toml/setup.pydeclaring a distributable package with no app entrypoint; or a Go module that builds a CLI binary only. Quote:"Library/CLI/package repo (publishing markers, no web framework or server entrypoint); nothing is deployed". - Before evaluating, quote: On pass, the path of the deploy artifact plus the 1-3 lines showing the deploy step, the platform config key, or the IaC deploy resource. On fail, quote the evidence that the app is a deployable production app (the framework dependency line, server entrypoint path, or build script) and name the deploy-config locations searched. Never pass on a filename alone without confirming it is not a stub or template.
- Report even on pass:
"Deploy path evidenced by <path>: <ci-deploy-job | platform-config (vercel/netlify/fly/render/...) | dockerfile+orchestration | iac>". - Detail on fail:
"Next.js app with a production build script, but no deploy workflow, platform config (vercel.json, netlify.toml, fly.toml), Dockerfile+orchestration, or IaC is committed. If you deploy via Vercel git integration, commit a vercel.json so the deploy path is evidenced in the repo."or".github/workflows/ci.yml runs lint and test only, the deploy job is commented out, and no platform config exists. Commit evidence of the real deploy path: re-enable the deploy job or add the platform config file." - Remediation: Commit the config your platform already honors: a minimal
vercel.jsonat the repo root (even just{ "framework": "nextjs" }),netlify.toml, orfly.toml; or add a deploy job to.github/workflows/deploy.ymlrunning your platform CLI. If you ship containers, commit the compose file or Kubernetes manifest beside theDockerfile. The platform keeps deploying via git integration; the committed file is the auditor-ready CC8.1 evidence.
External references
- soc2:2017 · CC8.1 — Changes to infrastructure and software are authorized, tested, approved, and implemented
- iso-27001:2022 · A.8.32 — Change management
- nist:rev5 · CM-3 — Configuration Change Control
Taxons
History
- 2026-07-03·v1.0.0·Initial soc2-readiness v1 authoring; evidence-pointer check that the deployment path (CI deploy job, platform config file, Dockerfile plus orchestration, or IaC deploy resources) is committed to the repo per SOC 2 CC8.1.·by soc2-readiness-v1-build