DevOps pipeline-as-code interview questions
Reviewed by Mark Dickie · Last updated
9 questions on this page you can answer and see marked on the spot. Go to the first one
Pipeline as code is the practice of defining your CI/CD pipeline in a version-controlled file rather than configuring it through a UI. For a DevOps interview, you should know how declarative and scripted pipeline formats differ, how to manage secrets and environment variables safely, and how to structure reusable pipeline stages across teams. Expect questions on idempotency, artifact promotion between environments, and how pipeline-as-code ties into infrastructure-as-code tools like Terraform or CloudFormation.
What does a DevOps interview test on pipeline-as-code?
Interviewers want to see that you can write, read, and debug a pipeline definition the same way you would application code. That means understanding the syntax of at least one major tool, knowing where configuration lives in the repo, and being able to explain why a pipeline failed by reading the file rather than clicking through a dashboard. They also check whether you understand the tradeoffs between declarative and imperative approaches.
| Concept | What to know | Common tools |
|---|---|---|
| Declarative vs. scripted | Declarative defines "what" the pipeline does; scripted defines "how" step by step | Jenkinsfile, GitHub Actions YAML |
| Secret management | How credentials are injected without hardcoding them in the repo | Vault, AWS Secrets Manager, Jenkins credentials store |
| Environment promotion | How an artifact moves from dev to staging to prod without being rebuilt | ArgoCD, Spinnaker, Jenkins promotion plugins |
| Trigger conditions | Branch rules, path filters, and event-based triggers | GitLab CI rules, GitHub Actions on: triggers |
| Reusable components | Shared libraries, composite actions, templates | Jenkins Shared Libraries, GitHub composite actions |
How do you structure a pipeline-as-code file for reuse?
- Store the pipeline file in the same repository as the application code, or in a dedicated config repo for multi-project setups.
- Break the pipeline into stages that map to your delivery lifecycle: build, test, package, deploy.
- Extract repeated logic into shared libraries or composite actions so teams inherit the same steps without copy-pasting.
- Use environment-scoped variables and conditionals so the same file handles dev, staging, and production deployments.
- Pin tool versions (container images, CLI versions) so builds stay reproducible across runs.
What are the most common pipeline-as-code mistakes in interviews?
Candidates often trip on secret handling. Storing tokens in plain environment variables inside the pipeline file is a red flag, and interviewers will push on this. Another frequent gap is confusing rebuild-with-redeploy: promoting an existing artifact between environments is not the same as rebuilding from source for each environment. Know the difference and be able to articulate when each approach is appropriate.
Key facts
- Tarmac has 27 DevOps interview questions on this topic, 25 of them on this page, at difficulty 1–5 of 5.
- Tarmac tracked 2,209 job postings asking for DevOps in September 2026.
- Roles asking for DevOps advertise a median base salary of £80,000, across 763 job postings as of September 2026.
- Tarmac last reviewed these DevOps interview questions on 13 October 2026.
At a glance
| Questions | 25 shown · 27 in the bank |
|---|---|
| Difficulty | 1–5 of 5 |
| Formats | Multiple choice, Short answer, Ordering, Fill in the blank, Design exercise, Multiple answer |
What you'll review
- pipeline as code
Practice questions
Try one before you open the answer. Pick an option and press Check; it's marked on the spot.
Which of the following is a defining characteristic of pipeline-as-code?#
Options
Show answer
Pipeline-as-code means defining CI/CD pipeline configuration in version-controlled text files such as YAML or Groovy, rather than configuring it manually through a web UI. This lets teams review, branch, and reproduce their build and deployment workflows exactly like application code.
Pipeline-as-code means the CI/CD pipeline definition lives in version-controlled text files—commonly YAML (e.g., GitHub Actions, GitLab CI) or code in a DSL like Groovy (Jenkinsfile). The other options each describe the opposite: UI-only configuration, compiled binaries, or manual stage management all defeat the purpose of treating the pipeline itself as reviewable, reproducible code.
Which statement correctly describes the 'pipeline as code' practice in CI/CD?#
Options
Show answer
Pipeline as code means defining the CI/CD pipeline in a version-controlled configuration file, such as a YAML file, stored in the same repository as the application source code. Because the pipeline definition is versioned, changes can be reviewed, diffed, and rolled back like any other code.
Pipeline as code means the pipeline's build, test, and deploy steps are described in a configuration file (for example YAML) that is kept in version control next to the application source. That lets teams review, diff, branch, and roll back pipeline changes the same way they handle application code. Configuring steps by hand in a CI server's web UI with no versioned copy is the opposite practice, running stages only on a local machine is not a CI pipeline, and scheduling backups through host cron is unrelated to pipeline definition.
In a GitHub Actions workflow YAML file, what is the name of the top-level key that specifies which events (such as push or pull_request) trigger the workflow to run?#
Show answer
The top-level key is on. For example, on: push means the workflow runs when a push event occurs.
GitHub Actions workflow files use the top-level on key to declare the events that should trigger the workflow. Common values include push, pull_request, workflow_dispatch, and others, and on can accept a single event string or a mapping of event names to their configuration.
What does the acronym HTTP stand for?#
Show answer
Hypertext Transfer Protocol
HTTP stands for Hypertext Transfer Protocol, the application-layer protocol used for transmitting hypermedia documents on the web. It is the foundational protocol of the World Wide Web, governing how browsers request and servers deliver web pages.
Which of the following is a primary benefit of defining a CI/CD pipeline as code in a version-controlled file (e.g., Jenkinsfile, .gitlab-ci.yml, or a GitHub Actions workflow YAML) rather than configuring it through a web UI?#
Options
Show answer
Pipeline-as-code lets you version, review, and branch pipeline changes alongside application code. Because the pipeline definition lives in a committed file (e.g., Jenkinsfile or .gitlab-ci.yml), every modification goes through the same code-review and history workflow as source code, giving you traceability, reproducibility, and team collaboration that a web-UI configuration cannot match.
Pipeline-as-code stores the pipeline definition as a text file in the same version-control repository as the application source. This means every change to the pipeline—new stages, modified build steps, environment updates—goes through the same commit, branch, review, and history workflow as application code. The claim that the pipeline executes faster because the YAML definition is compiled to native machine code before running is wrong because YAML is parsed and interpreted, not compiled to native code. The claim that the pipeline becomes immune to infrastructure outages because the definition is stored as text is wrong because storing the definition as text has no bearing on whether the CI/CD infrastructure or target environments are available. The claim that pipeline-as-code eliminates the need for build tools, test frameworks, or deployment dependencies is wrong because the pipeline still orchestrates real build tools, test runners, and deployment tooling—pipeline-as-code does not remove those dependencies.
In a .gitlab-ci.yml pipeline, if a job does not specify a stage keyword, which default stage is it automatically assigned to?#
Show answer
The test stage. GitLab CI/CD's built-in default stages are .pre, build, test, deploy, and .post, and a job with no stage keyword is placed in test.
GitLab CI/CD ships with the built-in default stages .pre, build, test, deploy, and .post (in that order). When a job definition omits the stage key entirely, GitLab assigns it to test, the middle default stage, so verification jobs such as unit tests run there without requiring an explicit stage declaration.
A CI/CD pipeline defined as code in a .gitlab-ci.yml file includes the five stages listed below. Arrange them in the order they execute in a standard, linear pipeline flow (each stage completes before the next begins).#
Put these in order
Show answer
In a standard linear pipeline defined in .gitlab-ci.yml, the stages run in this order: check out source code, compile the application, run automated tests, deploy to staging, and deploy to production. Each stage must complete before the next begins, so code reaches production only after it has been built and validated.
Source code must be retrieved from the repository before anything can be compiled, so checkout comes first. The application is compiled next, and the automated tests then validate that build. Only after the tests pass is the code deployed to staging, and finally promoted to the production environment. Each step depends on the output of the one before it, so the order is strict.
In a pipeline-as-code approach (e.g., GitHub Actions workflow files, GitLab CI YAML, Jenkinsfile), what is the primary advantage of storing the pipeline definition in a version-controlled repository alongside the application source code?#
Show answer
Storing the pipeline definition in version control alongside source code lets the pipeline itself go through the same pull-request review, branch protection, audit history, and rollback processes as application code, making the CI/CD process reproducible, reviewable, and consistent across environments.
The key benefit of pipeline-as-code is that the pipeline definition lives in the same version control system as the application code, so changes to the pipeline are subject to the same review, audit, rollback, and collaboration workflows as any other code change. This is not about execution speed, since pipeline definitions are parsed regardless of where they are stored. It is also not about bypassing security, which would be a risk rather than a benefit, and not about hiding the definition, since keeping it in the repository increases its visibility to developers.
Name a real, widely-used mechanism that pipeline-as-code tools (such as GitHub Actions, GitLab CI/CD, or Jenkins Pipelines) provide to control whether a deployment job runs, and briefly describe how it works.#
Show answer
Conditional execution (gating) is the core mechanism: the deployment job only runs when a defined condition evaluates to true. Common implementations include environment-based approvals (requiring manual sign-off before production), branch filters (deploy only from the main branch), and status checks (deploy only after all upstream test jobs pass). These let teams encode safety policies directly in the pipeline definition.
Pipeline-as-code tools provide conditional execution to gate deployment jobs — the job runs only when its condition evaluates to true. Standard implementations include environment-based approvals (manual sign-off before production), branch filters (deploy only from the main branch), and status checks (deploy only after upstream tests pass). Any of these is a valid, real mechanism for controlling whether a deployment step fires, and all are encoded directly in the pipeline definition rather than in out-of-band configuration.
In a CI/CD pipeline that compiles source code into a deployable artifact, order these stages from first to last: checkout source, build, integration testing against the built artifact, deploy to staging, deploy to production.#
Show answer
The correct order is: checkout source → build → integration testing against the built artifact → deploy to staging → deploy to production. You must check out source before compiling; you must build the artifact before running integration tests against it; integration tests must pass before deploying to staging; and staging must be validated before promoting to production.
In this artifact-based CI/CD pipeline, each stage has a strict dependency on the previous one: source must be checked out before compilation; the artifact must be built before integration tests can run against it; integration tests must pass before deploying to staging; and staging must be validated before promoting to production. Specifying 'integration testing against the built artifact' removes the ambiguity of pre-build checks (lint, unit tests) that some pipelines run before the build step — those are not the stage being ordered here.
A developer commits a change to the main branch of a repository that uses pipeline-as-code (for example, a .gitlab-ci.yml file or a GitHub Actions workflow file). What does the CI/CD system do with the pipeline definition file? Explain which version of the file it uses for that run.#
Show answer
The CI/CD system reads the pipeline definition file from the commit that triggered the run and executes the stages, jobs, and steps exactly as defined in that version of the file. Each pipeline run therefore uses the definition as it existed at the commit being built, not a shared or centrally managed copy. If a feature branch modifies the file, that branch's pipeline uses the modified definition, which is what makes pipeline changes safe to review through pull requests.
In pipeline-as-code, the pipeline definition is versioned alongside the code. The CI/CD platform reads the definition file from the repository at the specific commit that triggered the run, and it executes the jobs defined in that version. This is why each branch or commit can carry a different pipeline, and why changes to the pipeline can be reviewed and tested through the same pull request process as application code. A shared or centrally managed template may exist, but the repository's own file at that commit is the authoritative definition for the run unless the file itself references an external template.
A pipeline-as-code file is typically written in a declarative format like YAML. Which of the following is a key characteristic of pipeline-as-code that distinguishes it from configuring pipelines through a CI/CD tool's graphical UI?#
Options
Show answer
Pipeline-as-code stores the pipeline definition as a text file in the application's repository, so it is versioned, diffable, and reviewable through pull requests like any other code. A UI-configured pipeline keeps its definition inside the CI/CD tool's database, where those changes are harder to track and review.
The distinguishing feature of pipeline-as-code is that the entire pipeline definition is a text file stored in version control. This gives it change history, diffs between versions, pull-request review, branching, and reproducibility. UI-configured pipelines lack these properties because their definition lives in the CI/CD tool's internal database rather than in the repository. The other choices are wrong: pipeline-as-code does not inherently reduce execution time, does not require a general-purpose language (the format is declarative YAML or similar), and still needs a CI/CD server to execute the pipeline.
What is the purpose of the needs keyword in a pipeline-as-code configuration (as used in GitLab CI/CD or similar tools)?#
Show answer
The needs keyword declares that a job depends on other named jobs, so it does not start until those jobs have completed successfully. This lets the pipeline run as a directed acyclic graph (DAG) of job dependencies: independent jobs run in parallel, and a dependent job such as deploy waits only for the jobs it needs, such as test, rather than for an entire stage.
The needs keyword defines explicit job-to-job dependencies. When job B declares needs: [jobA], the pipeline does not start job B until job A completes successfully. Because only the declared dependencies constrain ordering, jobs without a dependency between them can run in parallel, and the resulting structure is a directed acyclic graph of jobs. It is not about caching, artifacts, or environment variables, which are separate configuration concepts; it concerns execution ordering and job dependencies.
A team stores their CI/CD pipeline definition as a YAML file in their Git repository. A junior developer asks why they can't just configure the pipeline through the CI/CD tool's web UI instead. Give two concrete advantages of the pipeline-as-code approach over UI configuration.#
Show answer
Two concrete advantages: (1) Version history and auditability: every change to the pipeline is tracked in Git with a commit hash, author, timestamp, and diff, so you can see exactly when and why a pipeline stage was added or modified and roll back to any previous version. (2) Peer review through pull requests: proposed pipeline changes can be reviewed and approved by teammates before merging, so a risky change (such as adding a deploy step or changing environment variables) is caught and discussed before it reaches the main branch. UI-configured pipelines lack both of these because their configuration lives in the CI/CD tool's database, not in version control.
The two most cited advantages of pipeline-as-code over UI configuration are: (1) the pipeline definition is versioned in Git, giving full change history, diffs, and rollback capability; and (2) pipeline changes can go through pull-request review just like application code changes, adding a quality gate to pipeline modifications. UI-based configuration typically stores the pipeline in the tool's own database, where changes are not diffed, attributed to a commit, or reviewed before taking effect, which is why these two properties distinguish pipeline-as-code.
In a typical CI/CD pipeline defined as code, what is the role of the 'build' stage?#
Show answer
The build stage compiles source code (if applicable), installs dependencies, and packages the application into a deployable artifact, such as a container image, a JAR/WAR file, a bundled static asset directory, or a compiled binary. The output artifact is stored or cached so that downstream stages (test, deploy) use the exact same artifact rather than rebuilding it, which ensures consistency between what was tested and what is deployed.
The build stage turns source code into a runnable, deployable artifact by compiling code where needed, resolving dependencies, and packaging the result. The key principle is that this artifact is produced once and reused by all downstream stages, so the exact artifact that was tested is the one that gets deployed. Graders should look for the artifact concept, with compiling, packaging, or dependency resolution as supporting detail.
A team stores their Jenkins pipeline definition in a Jenkinsfile committed to the application repository. The Jenkinsfile loads a shared pipeline library from a separate Git repository via library 'shared-pipeline-lib' (no version or commit pinned). Which statement about this pipeline-as-code setup is correct?#
Options
Show answer
A change to the shared library's default branch can modify every consuming pipeline with no commit in any application repository. Because library 'shared-pipeline-lib' specifies no pinned version, Jenkins resolves the library from its default branch at each build, so the library and the Jenkinsfile are not coupled to the same commit and the library's changes are reviewed in its own repo, not the application's.
Because library 'shared-pipeline-lib' is declared without a version or commit qualifier, Jenkins resolves it from the library's default branch at build time. A merge to that default branch therefore changes the pipeline behavior for every application that loads it — even though none of those application repositories received a commit. The claim that every change to the shared library is reviewed through the application's pull-request process is wrong because the library lives in its own repository, so its changes are reviewed through that repository's PR process, not the application's. The claim that the pipeline is fully reproducible from the application repository's commit is wrong because the library is not pinned to the application repo's commit; only the Jenkinsfile is. The claim that moving pipeline logic into the shared library eliminates the need for a Jenkinsfile in each consuming application repository is wrong because a Jenkinsfile is still required in each application repo to declare the library load and any app-specific configuration.
In a well-designed pipeline-as-code workflow, each pipeline stage should be _____: re-running the stage on the same commit (or re-triggering the entire pipeline) should produce the same end state without accumulating side effects such as duplicate deployments or appended artifacts. This property makes stages safely retriable and the pipeline reproducible.#
Show answer
In a well-designed pipeline-as-code workflow, each pipeline stage should be idempotent: re-running the stage on the same commit (or re-triggering the entire pipeline) should produce the same end state without accumulating side effects such as duplicate deployments or appended artifacts. This property makes stages safely retriable and the pipeline reproducible.
Idempotency means running an operation once or many times yields the same end state, with no duplicate deployments, no appended artifacts, and no accumulated state. This is what makes pipeline stages safely retriable, since a failed stage can be re-run without partial-cleanup headaches, and what keeps the overall pipeline reproducible on the same commit. A stage that is merely deterministic can still accumulate side effects on each run, and the 'without accumulating side effects' clause in the prompt specifically distinguishes idempotency from determinism.
Which statement correctly identifies the defining characteristic of a pipeline-as-code approach compared with a traditional UI-configured CI/CD pipeline?#
Options
Show answer
Pipeline-as-code defines the CI/CD pipeline as version-controlled text files, such as a Jenkinsfile or GitLab CI YAML, stored in the application's repository. This lets pipeline changes be reviewed, branched, and tracked like source code, whereas a UI-configured pipeline keeps its settings in the CI/CD tool's internal database.
The defining trait of pipeline-as-code is that the pipeline itself is expressed as text (for example a Jenkinsfile or GitLab CI YAML) that lives in version control next to the application source. This makes pipeline changes reviewable, branchable, and historically traceable through the same workflow as code. A UI-configured pipeline keeps its settings in the CI/CD server's internal database, reachable through the web interface, which makes changes harder to review and audit. The other statements are wrong: storing the definition in the tool's database describes the UI approach, not pipeline-as-code; speed is not determined by how the pipeline is defined; and pipeline-as-code pipelines are commonly triggered by commits just like UI-configured ones.
You are the platform engineer responsible for a large monorepo shared by 12 product teams. Each team currently maintains its own Jenkinsfile, and the CI pipeline definitions have diverged wildly—some teams run tests in parallel, some not at all; secret handling ranges from hardcoded env vars to proper vault integration; and average CI runtime is 35 minutes. Leadership wants you to migrate everything to a single pipeline-as-code standard that lives in the repo itself, reduces average CI time by 50%, and enforces a shared security baseline while still letting each team customize build/test steps. The target CI/CD platform is GitHub Actions (you may use reusable workflows, composite actions, and matrix strategies). Design the pipeline-as-code architecture. Address: (1) how the shared pipeline skeleton and per-team customization points are structured in code, (2) how secrets are injected securely and uniformly, (3) how you achieve the 50% runtime reduction (caching, parallelism, selective execution), and (4) how you roll out the standard across 12 teams without a big-bang migration.#
Show answer
We introduce a single reusable workflow at .github/workflows/ci.yml that acts as the shared entry point for every team's pull request and push events. This reusable workflow calls a set of composite actions organized by concern: setup (toolchain + caching), security-scan (SAST, dependency scanning, secret detection), build, test, and publish. Per-team customization is achieved through convention-based discovery: each team's package directory contains a .ci/build.sh and .ci/test.sh (or a ci-config.yml declaring custom steps). The reusable workflow dynamically includes these scripts at the appropriate stage using working-directory and conditional job steps. Teams that need entirely custom logic can supply a composite action at packages/<team>/.ci/custom-action/ that the shared workflow invokes if present, keeping the security baseline (SAST, dependency scanning) non-negotiable while allowing build/test flexibility.
Secrets are managed centrally: organization-level secrets store shared credentials (e.g., artifact store, vault endpoint), and per-team secrets are scoped to GitHub Environments mapped to each package path via deployment-environment naming conventions. For sensitive infrastructure, we federate with OIDC to HashiCorp Vault, issuing short-lived, per-team roles so no static credentials live in GitHub. The reusable workflow references ${{ secrets.* }} only through the environment-scoped injection, preventing teams from accessing each other's secrets.
Runtime reduction comes from three techniques. First, dependency and build-output caching via actions/cache keyed on lockfile hashes, plus Docker layer caching for containerized builds. Second, selective execution: we use dorny/paths-filter or tj-actions/changed-files to detect which packages changed and dynamically generate a matrix of only the affected packages, skipping build/test for unchanged areas. Third, test parallelism: each package's test suite is split into shards using a matrix strategy (e.g., shard: [1/4, 2/4, 3/4, 4/4]) with a test-splitter tool, and independent packages run concurrently as separate matrix entries.
Rollout is phased: we start with two pilot teams, running the new GitHub Actions pipeline in shadow mode alongside their existing Jenkinsfile for two weeks. We compare results and timing, then publish a migration checklist (provide .ci/ scripts, declare environment mappings, validate secret access). Each subsequent team migrates one sprint at a time, with a 1-week overlap period where both pipelines run. A migration tracking dashboard (built from workflow run data) shows which teams have migrated, their CI time delta, and any failing checks. Legacy Jenkinsfiles are archived (not deleted) only after a team's new pipeline has been green for two consecutive weeks, preventing a big-bang failure.
This design exercise tests senior-level pipeline-as-code architecture: structuring reusable workflows with controlled customization, centralized secret injection, concrete monorepo-specific runtime optimizations, and a realistic phased rollout. Difficulty 4 because it requires synthesizing GitHub Actions primitives (reusable workflows, composite actions, matrix strategies, environments/OIDC) with organizational concerns (12 teams, divergence, incremental migration) and quantifiable targets (50% runtime reduction).
A team uses GitHub Actions for CI on pull requests. Their workflow is triggered with on: pull_request_target, then checks out the PR head ref via actions/checkout@v3 with ref: ${{ github.event.pull_request.head.sha }} and runs npm test on that code. A maintainer approves the PR and the workflow executes. Why do security reviewers flag this configuration as unsafe?#
Options
Show answer
Using pull_request_target and then checking out the pull request's own code is unsafe because that event runs the workflow in the base branch's context with full access to repository secrets and a write-capable GITHUB_TOKEN. Untrusted PR build steps can therefore read and exfiltrate those secrets. Use pull_request for untrusted builds, or restrict pull_request_target to non-build actions that never execute the PR's code.
The pull_request_target event is designed so that the workflow definition comes from the base (trusted) branch, giving it access to repository secrets and a write-capable GITHUB_TOKEN. However, when the workflow also checks out and runs the pull request's own code — as this configuration does by setting ref to the PR head SHA — that untrusted code executes with those same elevated privileges. A malicious contributor could add a script to the PR that reads environment-injected secrets and exfiltrates them. The correct mitigation is to use pull_request for building and testing untrusted code, since that event runs forked PRs without secret access and with a read-only token, or to restrict pull_request_target to trusted, non-build actions such as labeling or commenting. The option stating that pull_request_target does not trigger on forks is false — triggering on forks is precisely its purpose. The option about npm test being disallowed has no basis. The option about a actions/checkout@v3 token-leak vulnerability describes no real, known issue.
You are reviewing a team's pipeline-as-code implementation across 12 microservices in a monorepo using GitHub Actions, where each service has its own workflow file. Describe at least two practices the team should adopt and at least one anti-pattern they should avoid, with brief justification for each.#
Show answer
The team should keep the pipeline definitions in the same Git repository as the code they build, so pipeline changes go through the same review and branch-protection process as application code and can be reverted and audited alongside it. They should also move the shared build, test, scan, and deploy steps into reusable, versioned workflows or composite actions, so the 12 services do not drift apart in their YAML and maintenance stays manageable. Finally, they should lint workflow files with actionlint or yamllint as a pre-merge CI check, so structural and syntax errors are caught at review time rather than at deploy time. An anti-pattern to avoid is hardcoding credentials, such as base64-encoded secrets, inside pipeline files; secrets should be injected at runtime from a platform secret store or external secrets manager. Another is giving the CI runner blanket admin access to the production cluster, which violates least-privilege; each stage should get only the permissions it needs, ideally through short-lived OIDC-issued credentials.
A strong answer names at least two practices and at least one anti-pattern, each with a reason. Keeping pipeline definitions in the application repository makes pipeline changes reviewable, revertable, and auditable together with code changes. Extracting shared build, test, scan, and deploy logic into reusable, versioned workflows or composite actions prevents YAML drift across the 12 services and reduces maintenance. Linting workflow files with actionlint or yamllint as a pre-merge gate catches syntax and structural errors at review time. Storing credentials such as base64-encoded secrets in pipeline files is an anti-pattern because they should be injected at runtime from a secret store. Granting the runner blanket production admin access violates least-privilege; scoping each stage to the permissions it needs, typically with short-lived OIDC-issued credentials, is the preferred approach.
You are the platform engineer responsible for the CI/CD strategy at a company with a monorepo containing 15 microservices (Go, Python, TypeScript) plus a shared common library. The company uses GitHub as its VCS and GitHub Actions for CI/CD. Requirements: (1) Only the services that changed (plus their dependents) should be built and tested on each push, not the entire monorepo. (2) Artifacts must be built once and promoted through dev, staging, and production without rebuilding. (3) Production deployments require approval from the current on-call engineer, whose identity rotates on a schedule. (4) The shared common library's security-critical updates must trigger builds for all dependent services. (5) Each environment has its own set of secrets that must not be accessible from other environments. Design the pipeline-as-code architecture: describe how you detect which services changed on a push event, how you structure reusable pipeline logic, how artifacts are built once and promoted, how production deployment gates work (including how a rotating on-call role is reconciled with GitHub Environments' static required-reviewer lists), and how secrets are isolated per environment.#
Show answer
Change detection: a detect-changes job runs on push and compares github.event.before (the branch head before the push) with github.sha (the pushed head), so multi-commit pushes are covered; a paths filter such as dorny/paths-filter yields the changed top-level service directories. If common/ changed, a per-service DEPENDENCIES manifest adds every dependent service to the changed set, and only those services proceed (via a matrix). Reusable logic: one reusable workflow (workflow_call) holds the shared build, test, and deploy jobs and is parameterised by a thin per-service config (language, build command, deploy target); repeated steps live in composite actions under .github/actions/. Build once: each changed service produces a single container image tagged with the commit SHA and pushed to GHCR; dev, staging, and production deploy jobs all reference that same SHA tag, so promotion means redeploying the existing image to the next environment, never rebuilding. Prod gate: the production job declares environment: production, whose required reviewer is the team @org/on-call-approvers. Because GitHub accepts only static users or teams as reviewers, a scheduled job or PagerDuty webhook calls the GitHub Teams REST API to set that team's membership to the current on-call engineer from the rotation; the approval, approver, and timestamp are recorded in the run's audit log. Secrets: dev, staging, and production are separate GitHub Environments, each with its own scoped secrets, and a job can read only the secrets of the environment it declares. Cloud access uses OIDC with one IAM role per environment whose trust policy accepts only that environment's subject claim (for example repo:org/repo:environment:production), so the dev role cannot reach the production cluster.
This is an open design question with several defensible architectures, so it stays a SHORT_ANSWER graded against the sample answer's five required components: push-based change detection with dependency expansion, reusable workflow plus composite actions, a single SHA-tagged image promoted across environments, a team-based production gate synced to the rotation via API, and per-environment GitHub Environment secrets with OIDC role scoping. The sample answer was corrected in one respect: the original tied detection to the commit's parent, which is wrong for multi-commit pushes, so the reference now compares the branch's previous head (github.event.before) with the pushed head (github.sha). Keywords target the mandatory SHA-tagged artifact, the OIDC per-environment isolation, the reviewer team, and the on-call rotation.
You are the platform lead for a 400-engineer organization with 60+ microservices spanning 5 teams. Each service has its own repository and its own CI/CD needs (build, test, security scan, deploy to dev/staging/prod). Teams currently write ad-hoc Jenkinsfiles or GitHub Actions workflows with no shared standards, resulting in inconsistent security practices, duplicated effort, and frequent production incidents from missing gates.#
Show answer
Architecture Overview
The system has three layers: (1) the service manifest (team-owned, in-repo), (2) the platform render engine (platform-team-owned, in a central repo), and (3) the generated pipeline (ephemeral, never hand-edited).
1. Service Manifest (service.yaml)
Each repo contains a minimal manifest:
apiVersion: platform.io/v1
kind: ServicePipeline
metadata:
name: payments-api
team: payments
spec:
build:
type: gradle
runtime: java21
deploy:
environments: [dev, staging, prod]
strategy: blue-green
healthCheckPath: /actuator/health
# Teams CANNOT declare gates here — gates are platform-controlled.
extensions:
- name: integration-test-sandbox
uses: platform-gates/custom-integration-test@v3
with:
sandboxUrl: https://sandbox.example.com
The manifest declares what the service is and where it deploys, but never what gates run. The extensions field is the only extensibility point and can only reference platform-approved, SHA-pinned reusable components.
2. Platform Render Engine
A central repository (platform-pipelines) contains:
- A set of reusable workflow templates (GitHub Actions reusable workflows, or Tekton Pipeline definitions) one per lifecycle stage:
build,security-gates,deploy. - A render CLI (
platform-pipeline) that reads aservice.yaml, validates it against a JSON schema, and emits the final pipeline file (e.g.,.github/workflows/generated-ci.yml) — though in practice the workflow is a thin stub that calls the platform's reusable workflows.
The actual generated workflow is a minimal stub:
name: CI
on:
push: { branches: [main] }
pull_request: {}
jobs:
ci:
uses: platform-org/platform-pipelines/.github/workflows/[email protected]
with:
manifestPath: service.yaml
secrets: inherit
This stub is the only thing in the service repo's .github/workflows/ directory. It delegates entirely to the platform workflow.
3. Non-Bypassable Mandatory Gates
The platform reusable workflow ([email protected]) is the single source of truth for gate ordering and enforcement. It:
- Runs SAST (Semgrep), dependency scanning (Trivy), and container image signing (cosign) as required steps — they are hardcoded in the platform workflow and cannot be disabled by the manifest.
- The prod deploy job requires an
environment: productionapproval gate configured at the GitHub org level with required reviewers. - Branch protection rules (enforced via GitHub Org settings or Terraform-managed) mark the platform workflow's status checks as required. Since the stub workflow always delegates to the platform workflow, the checks always come from the platform — a team cannot substitute their own workflow that skips gates because the required-status-check names are pinned to the platform workflow's job names.
If a team removes the stub workflow or the manifest, branch protection prevents merges because the required checks never report.
4. Secret Scoping and Delivery
Secrets are stored in HashiCorp Vault, organized by path: secret/data/payments/dev, secret/data/payments/staging, secret/data/payments/prod. The platform workflow authenticates to Vault using OIDC federation — the GitHub Actions job exchanges its OIDC token for a short-lived Vault token scoped to that team's environment path. No static credentials exist in GitHub Actions secrets. The manifest's deploy.environments field determines which Vault paths the platform workflow requests, so a dev-only service cannot access prod secrets.
5. Centralized Gate Rollout
To add a new mandatory gate (e.g., SBOM generation):
- The platform team adds the step to
service-ci.ymlin theplatform-pipelinesrepo. - They tag a new version (e.g.,
v14.3.0) and update a version manifest (a single file in the platform repo, or an org-level variable) that the render CLI reads. - On the next pipeline run, each service's stub workflow resolves
@v14.3.0(if using a moving tag) or the render CLI is re-run to bump the SHA-pinned reference.
Using a moving tag (@v14) means all services pick up the new gate automatically on their next push. Using SHA-pinning with a renovate bot bumping the SHA across all repos provides supply-chain security while still automating rollout.
6. Local Dry-Run
The render CLI supports:
platform-pipeline validate --manifest service.yaml # schema validation
platform-pipeline render --manifest service.yaml --dry-run # emits full pipeline to stdout
platform-pipeline render --manifest service.yaml --output .github/workflows/generated-ci.yml
Teams run validate and render --dry-run in a pre-commit hook or local dev workflow. The CLI is distributed as a container image and a Homebrew formula, versioned to match the platform workflow tag.
7. Incremental Migration
- A migration dashboard (backed by a scan of all repos for
service.yamlpresence) tracks adoption. - Teams opt in by adding a
service.yamland the stub workflow. Legacy pipelines continue to run in parallel. - Branch protection is updated per-repo to require the platform checks only after the team confirms the new pipeline is green.
- A sunset date (e.g., 90 days out) is communicated for legacy pipeline support, after which the platform CI runners stop accepting non-platform workflows.
- The platform team provides a migration generator that analyzes an existing Jenkinsfile/GitHub Action and produces a best-effort
service.yamlto reduce manual work.
This design exercise tests a staff-level engineer's ability to architect a pipeline-as-code platform that balances team autonomy with centralized control. The rubric evaluates five distinct architectural concerns: manifest-driven generation, non-bypassable enforcement (the hardest part — requiring a concrete mechanism, not just a policy statement), secret scoping via OIDC federation, centralized rollout via versioned reusable workflows, and the operational concerns of local dry-run and incremental migration. A strong answer must address all five with concrete, implementable mechanisms.
You are the DevOps platform lead for an organization with 200+ developers across 12 teams. Each team owns 3–8 microservices in a single Git monorepo. Every service has its own build, test, and deployment requirements, but all services share a common set of compliance gates (SAST, SCA, container image scanning, license checking) that must pass before any artifact reaches production. Teams deploy to 3 environments (dev, staging, prod) across 2 cloud providers (AWS and GCP). Design a pipeline-as-code architecture that: (a) keeps each team's service-specific pipeline logic in their own directory while enforcing the shared compliance gates centrally, (b) prevents any single team from disabling or bypassing a compliance gate, (c) supports reusable templates so teams don't reinvent common steps, (d) allows the platform team to roll out changes to all pipelines without requiring every team to open a PR, and (e) maintains an audit trail of what pipeline definition was used for each production deployment. Describe your architecture, tooling choices, and the key mechanisms that enforce each requirement.#
Show answer
Repository layout: each service lives under services/<team>/<service>/ with its own .pipeline.yml for service-specific build, test and deploy steps. A separate infra/ directory owned by the platform team holds a versioned shared CI/CD library (for example a GitLab CI template project or a GitHub Actions reusable-workflow repository) that defines the compliance gates as mandatory steps. (a) The top-level pipeline file is platform-controlled and includes the team's service pipeline as a child, wrapping it with pre-deployment gates; teams can add steps but cannot reorder or remove the gate sequence. (b) Enforcement: CODEOWNERS requires platform-team approval for changes to infra/ and the top-level pipeline file, and branch protection with required status checks means the gate jobs must succeed before merge and deploy; the gates run in a pipeline stage the service config cannot edit. (c) Reuse: the shared library exposes parameterized templates (build, test, deploy) that teams include by reference. (d) Rollout: the library is semver-versioned and imported by reference (e.g. ref: v2.3.0); the platform team publishes a new version and updates the default reference in the platform-owned top-level config that every service inherits, so no per-team PR is needed; teams needing stability can pin a major version. Multi-cloud: deploy templates take cloud_provider and environment inputs and hide AWS vs GCP specifics behind a common interface; credentials, regions and cluster endpoints come from a central secrets manager such as HashiCorp Vault, keyed by environment and provider, never stored in the repo. (e) Audit: at execution time the fully resolved pipeline definition (after includes and template expansion) is serialized and its SHA-256 hash is stored with the build artifact in the artifact registry; the deployment metadata records that hash, the shared library version and the Git commit SHA, plus the compliance gate results, giving an immutable link from each production deployment to the exact pipeline definition that produced it.
This is an open design question with no single key, so it stays a short-answer item graded against the expected keywords and the sample answer. A strong answer must cover all five requirements: a centrally owned compliance-gate stage that teams cannot edit (enforced by CODEOWNERS and required checks), per-team service directories separated from platform code, reusable parameterized templates, versioned shared library references that let the platform roll out changes from a single platform-owned file, and an audit trail that hashes the fully resolved pipeline definition and records it alongside the commit SHA and library version in deployment metadata. Multi-cloud and multi-environment handling should use a provider-agnostic deploy interface with secrets pulled from a central store.
You are designing a pipeline-as-code system for a monorepo containing 40 microservices. Which of the following statements about selective pipeline execution (only running CI/CD for services affected by a change) are correct? Select all that apply.#
Options
Pick every one that applies.
Show answer
Path-based triggering via a service-to-directory mapping, dependency-graph traversal that finds services transitively depending on a changed shared library, and diffing against the merge-base are correct for selective pipeline execution. The claim that selective execution removes the need for integration testing before production is false, since it only shortens CI feedback time.
Path-based triggering with a service-to-directory mapping is the foundational approach to selective execution: it identifies which services' source files were directly modified by a commit. Dependency-graph tools such as Bazel or Nx go further by traversing the build dependency graph to find not just directly changed services but also downstream services that transitively depend on changed shared libraries, so a change to a common library triggers rebuilds for all consumers. Diffing against the merge-base of the source branch and the default branch is the correct Git strategy because it captures the cumulative changes on the branch. The claim that selective execution makes integration testing before production unnecessary is incorrect: selective execution is a CI-feedback-time optimization that speeds up developer iteration, but it does not replace comprehensive integration testing prior to production deployment.
Related interview questions
Job market
See devops salaries and hiring demand from live job postings.
The other 2 questions
This page shows 25 and marks what you pick. That's as far as a page can go. A free account opens the other 2 and keeps every answer. What you miss comes back until it's right: after a day, then at longer gaps.
Free · the whole bank · 100 marked answers per 30 days · written feedback on the paid plan