Try 10 focused GitHub Actions GH-200 questions on Secure Automation, with explanations, then continue with IT Mastery.
Open the matching IT Mastery practice page for timed mocks, topic drills, progress tracking, explanations, and full practice.
Try GitHub Actions GH-200 on Web View full GitHub Actions GH-200 practice page
| Field | Detail |
|---|---|
| Exam route | GitHub Actions GH-200 |
| Topic area | Secure and Optimize Automation |
| Blueprint weight | 15% |
| Page purpose | Focused sample questions before returning to mixed practice |
Use this page to isolate Secure and Optimize Automation for GitHub Actions GH-200. Work through the 10 questions first, then review the explanations and return to mixed practice in IT Mastery.
| Pass | What to do | What to record |
|---|---|---|
| First attempt | Answer without checking the explanation first. | The fact, rule, calculation, or judgment point that controlled your answer. |
| Review | Read the explanation even when you were correct. | Why the best answer is stronger than the closest distractor. |
| Repair | Repeat only missed or uncertain items after a short break. | The pattern behind misses, not the answer letter. |
| Transfer | Return to mixed practice once the topic feels stable. | Whether the same skill holds up when the topic is no longer obvious. |
Blueprint context: 15% of the practice outline. A focused topic score can overstate readiness if you recognize the pattern too quickly, so use it as repair work before timed mixed sets.
These questions are original IT Mastery practice items aligned to this topic area. They are designed for self-assessment and are not official exam questions.
Topic: Secure and Optimize Automation
A repository uses deployment environments with these settings:
| Environment | Required reviewers | Secret DEPLOY_URL |
|---|---|---|
staging | none | staging.example |
production | 1 reviewer | prod.example |
There is no repository-level secret named DEPLOY_URL.
A push to main triggers this workflow:
name: release
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: echo "package" > app.txt
- uses: actions/upload-artifact@v4
with:
name: app
path: app.txt
deploy-staging:
needs: build
runs-on: ubuntu-latest
environment: staging
steps:
- uses: actions/download-artifact@v4
with:
name: app
- run: echo "Deploying to ${{ secrets.DEPLOY_URL }}"
deploy-prod:
needs: deploy-staging
runs-on: ubuntu-latest
environment: production
steps:
- run: echo "Deploying to ${{ secrets.DEPLOY_URL }}"
build and deploy-staging both complete successfully. No one has approved the production environment yet. Which statement matches GitHub Actions behavior?
Options:
A. deploy-prod starts immediately, but its secret is blank until approval is granted.
B. Both deployment jobs would have required approval because both jobs declare environment:.
C. deploy-prod is skipped because the uploaded artifact can be downloaded only once.
D. deploy-prod waits for approval; none of its steps run; deploy-staging used the staging environment secret.
Best answer: D
Explanation: Environment protections apply to the specific environment a job targets. Here, deploy-staging can run normally and use staging secrets, while deploy-prod pauses before any steps start because production requires reviewer approval.
In GitHub Actions, needs controls job order, and environment protection rules control whether a specific deployment job can start. After build succeeds, deploy-staging runs because the staging environment has no required reviewers. Its DEPLOY_URL value comes from the staging environment secret, since no repository-level secret with that name exists.
When deploy-prod becomes eligible, GitHub checks the production environment rules first. Because approval is required, the job waits and is not dispatched to a runner yet. That means no deploy-prod steps execute and its environment secret is not exposed before approval. Artifacts uploaded in one job can be downloaded by later jobs in the same workflow run, so the earlier artifact step does not block this behavior.
The key point is that protection is per environment, not for every job that uses environment:.
Topic: Secure and Optimize Automation
A service repository deploys to production from main with this workflow:
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- run: ./build.sh
deploy-prod:
needs: build
runs-on: ubuntu-latest
steps:
- run: ./deploy-prod.sh
Builds must continue automatically on every push. The deploy-prod job must pause until a member of the ops-reviewers team approves the production deployment. Which configuration best meets this requirement?
Options:
A. Create a production environment with ops-reviewers as required reviewers, and set environment: production on deploy-prod.
B. Add an if condition so only specific usernames can run deploy-prod.
C. Replace push with workflow_dispatch, and allow only ops engineers to start the workflow.
D. Protect main with required pull request reviews, and keep deploy-prod running automatically after merges to main.
Best answer: A
Explanation: Use a GitHub Actions environment for production and add required reviewers to that environment. When the deploy job references that environment, GitHub pauses the job until an authorized reviewer approves it, which directly satisfies the requirement.
Environment protection rules are the built-in way to require human approval before a sensitive job deploys. Configure a production environment in the repository, add the ops-reviewers team as required reviewers, and reference that environment from the deploy-prod job.
deploy-prod:
needs: build
runs-on: ubuntu-latest
environment: production
steps:
- run: ./deploy-prod.sh
When the workflow reaches that job, GitHub holds the deployment until an allowed reviewer approves the environment. This preserves automatic build execution on every push while adding a deployment-specific approval gate. Branch protection, manual triggers, and username checks can restrict code changes or who starts a run, but they do not provide the same built-in pre-deployment reviewer control.
main, but it does not require approval for each production deployment job.workflow_dispatch changes how runs start and removes the automatic push flow without adding an environment approval gate.if condition only controls job logic based on identity and does not create an auditable reviewer approval step.Topic: Secure and Optimize Automation
An organization wants teams to keep using currently approved GitHub Actions. If a pull request adds a new third-party or unverified action, or changes an existing uses: reference, the security team must review it before the workflow can be used on the protected main branch. Which configuration best meets this requirement?
Options:
A. Use first-time contributor workflow approvals and keep the repository’s default action policy
B. Use an org Actions allowlist with full-SHA pinning and CODEOWNERS review on workflow files
C. Use environment required reviewers for all jobs and allow third-party actions pinned to tags
D. Use restricted self-hosted runners for all workflows and set GITHUB_TOKEN permissions to read-only
Best answer: B
Explanation: The best fit is to combine governance at the policy layer with review at the pull request layer. An Actions allowlist limits which actions can run, and required CODEOWNERS review on workflow files makes the security team approve any newly introduced or changed action reference before it reaches main.
GitHub Actions does not give trusted maintainers a general runtime prompt to approve each newly added marketplace action. The durable approach is to control both what can run and who must review the change that introduces it. Use an organization Actions policy to allow only approved actions or reusable workflows, and require full commit SHA pinning for integrity. Then protect workflow files with a ruleset or branch protection that requires CODEOWNERS review by the security team. That way, a pull request that adds or changes a uses: reference cannot land on main without review, and even after approval only allowlisted, immutable action versions can run. Environment approvals, fork-run approvals, and runner isolation address different risks but do not create an approval flow for newly introduced actions.
Topic: Secure and Optimize Automation
Your repository is configured to retain workflow logs and artifacts for 30 days. A nightly matrix run failed 5 days ago. The run is still visible in Actions, and its job logs open normally, but each failure-bundle artifact can no longer be downloaded.
Exhibit:
- name: Upload failure bundle
if: failure()
uses: actions/upload-artifact@v4
with:
name: failure-bundle-${{ matrix.os }}
path: out/debug/
retention-days: 3
What is the most likely cause?
Options:
A. Matrix artifact links broke when the job names changed
B. The if: failure() condition prevented post-run artifact retention
C. A shorter artifact retention overrode the repository default
D. The hosted runner deleted the stored artifact at teardown
Best answer: C
Explanation: actions/upload-artifact can set retention for a specific artifact shorter than the repository default. Here, the artifact was uploaded with retention-days: 3, so it expired before the 30-day run logs did.
The key concept is that artifact retention can be configured per upload, while workflow logs follow the repository or organization retention setting. In this run, the repository keeps logs and artifacts for up to 30 days by default, but the failure-bundle upload explicitly set retention-days: 3. That means the artifact can expire after 3 days even though the run record and logs remain available.
if: failure() only controls whether the upload step runs after a failed job; it does not shorten retention. Matrix job naming also does not invalidate stored artifacts from an existing run, and hosted runner teardown does not remove artifacts that were already uploaded to GitHub storage.
When failed-run evidence disappears sooner than expected, inspect the upload-artifact step first for a shorter retention-days value.
if: failure() confuses step execution with retention; it decides when the upload happens, not how long GitHub stores it.Topic: Secure and Optimize Automation
You add artifact attestations to a release workflow. The build job succeeds, but the production deploy job is blocked by an organization policy. The repository uses a shared self-hosted runner group managed outside the release team.
jobs:
build:
runs-on: [self-hosted, linux, shared]
permissions:
contents: read
id-token: write
attestations: write
steps:
- uses: actions/checkout@v4
- run: ./scripts/build.sh
- uses: actions/attest-build-provenance@v3
with:
subject-path: dist/app.tgz
Verification: attestation valid
Policy: blocked
Reason: builder environment not trusted
What is the best explanation for the block?
Options:
A. The build job also needs contents: write permission.
B. actions/checkout must be pinned to a full SHA.
C. The attestation is valid, but the shared self-hosted runner is not trusted.
D. subject-path must reference an uploaded workflow artifact.
Best answer: C
Explanation: The attestation is valid, so the artifact can be tied to the recorded workflow run. But provenance is only as trustworthy as the builder, and a shared self-hosted runner outside the team’s control can still undermine the build, so the policy blocks deployment.
A GitHub artifact attestation can prove that dist/app.tgz came from the recorded workflow run, and the log confirms that provenance verification passed. But that assurance depends on trusting the workflow, its dependencies, and the runner environment. Because this job ran on a shared self-hosted runner managed outside the release team, the attestation cannot by itself prove the build environment was safe from tampering.
Pinning actions is also a good hardening step, but the immediate reason for the block is the untrusted runner environment named in the policy result.
contents: write is not the issue here; the attestation already verified, and the policy message points to builder trust.actions/checkout to a full SHA improves supply-chain integrity, but it is not required for attestation verification and does not match the stated block reason.subject-path can point to a file created in the workspace; it does not have to be an uploaded workflow artifact.Topic: Secure and Optimize Automation
A team wants broad test feedback without running unnecessary Windows jobs or unlimited parallel work. A push triggers this workflow. precheck succeeds. In the test matrix, only windows-latest with Node 20 fails; every other matrix job succeeds.
name: ci
on: [push]
jobs:
precheck:
runs-on: ubuntu-latest
steps:
- run: echo "lint passed"
test:
needs: precheck
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
max-parallel: 2
matrix:
os: [ubuntu-latest, windows-latest]
node: [18, 20]
include:
- os: ubuntu-latest
node: 22
exclude:
- os: windows-latest
node: 18
steps:
- run: echo "test ${{ matrix.os }} / ${{ matrix.node }}"
- if: ${{ matrix.os == 'windows-latest' && matrix.node == 20 }}
run: exit 1
package:
needs: test
runs-on: ubuntu-latest
steps:
- run: echo "package"
Which statement matches GitHub Actions behavior for this run?
Options:
A. Four test jobs are created; GitHub-hosted runners ignore max-parallel, so all four can start together; package runs if any one matrix copy succeeds.
B. Five test jobs are created; the include entry duplicates all Ubuntu combinations; package is canceled immediately when the Windows job fails.
C. Three test jobs are created; package runs after the first two succeed because fail-fast: false allows partial success.
D. Four test jobs are created; at most two run at once; package is skipped after the matrix completes because one test job failed.
Best answer: D
Explanation: The matrix expands to four jobs: Ubuntu 18, Ubuntu 20, Windows 20, and the added Ubuntu 22. max-parallel: 2 caps concurrent matrix jobs, fail-fast: false keeps the remaining matrix jobs running after the Windows failure, and package is skipped because its needs dependency did not fully succeed.
This workflow uses matrix shaping and concurrency controls to balance feedback and cost. Start with the Cartesian product of os and node: 4 combinations. The exclude entry removes windows-latest with Node 18, leaving 3. The include entry then adds one extra combination, Ubuntu with Node 22, for a total of 4 matrix jobs.
precheck runs first because test depends on it.precheck succeeds, no more than 2 test matrix jobs can run at the same time because of max-parallel: 2.windows-latest with Node 20 fails, the other matrix jobs continue because fail-fast is false.package waits for the full test matrix and is skipped because one matrix copy failed.The key trap is confusing fail-fast: false with downstream partial success; it only stops sibling cancellation.
fail-fast: false keeps remaining matrix jobs running, but it does not let a downstream needs job start after only some copies succeed.include adds one explicit combination; it does not create another cross-product of Ubuntu values.max-parallel; the matrix still runs only up to two jobs concurrently.Topic: Secure and Optimize Automation
A repository has a production environment with required reviewers. The deploy job authenticates to the cloud by OIDC and does not need repository write access. The team wants tests on every push and pull request, but production deployment must run only after test succeeds on a push to main. Pull requests must not trigger a production approval request.
name: ci-cd
on:
push:
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: ./test.sh
deploy:
needs: test
runs-on: ubuntu-latest
environment: production
permissions: write-all
steps:
- uses: actions/checkout@v4
- run: ./deploy.sh
Which edit best meets these requirements?
Options:
A. Keep the triggers, but put the branch check on the deploy step and leave permissions: write-all.
B. Add if: github.event_name == 'push' && github.ref == 'refs/heads/main' to deploy, and set permissions to contents: read and id-token: write.
C. Change the workflow trigger to only push on main, and keep the deploy job as written.
D. Remove environment: production and rely on a branch condition in deploy to protect releases.
Best answer: B
Explanation: The safest fix is to gate the entire deploy job with a job-level if for push to main and reduce token permissions to only what deployment needs. That keeps PRs running tests without ever entering the protected production environment or keeping unnecessary write access.
Environment protection rules apply when a job targets an environment, so the important control is to stop the deploy job from starting unless the event is a push to main. Because deploy already has needs: test, it will still wait for tests to pass first; once the job is eligible, the production environment can enforce required reviewers. Reducing permissions from write-all to contents: read plus id-token: write follows least privilege for a job that only checks out code and obtains cloud credentials through OIDC.
if to block PR deployments entirely.environment: production so approvals still protect real deployments.A step-level condition is too late, because the job would still target the protected environment before that step runs.
main breaks the requirement to run tests on pull requests.deploy job from targeting production, so a PR can still trigger environment approval flow.Topic: Secure and Optimize Automation
A repository contains a Node.js app in web/. The repository root has no lockfile; only web/package-lock.json exists. The team wants faster repeated workflow runs, but the cache must be invalidated when web/package-lock.json changes.
name: web-ci
on:
push:
paths:
- 'web/**'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
working-directory: web
- run: npm test
working-directory: web
Which edit best satisfies this requirement?
Options:
A. Add cache: npm and cache-dependency-path: web/package-lock.json.
B. Cache ~/.npm with key ${{ github.sha }}.
C. Add only cache: npm to actions/setup-node.
D. Cache web/node_modules with key ${{ runner.os }}-node.
Best answer: A
Explanation: Use actions/setup-node caching with cache: npm and point cache-dependency-path to the actual lockfile in web/. That speeds repeated npm ci runs while ensuring the cache key changes when the app’s dependencies change.
For dependency caching, the key should reflect the dependency definition, not just the branch, OS, or commit. In this workflow, the dependency definition is web/package-lock.json, and the repository root does not contain a lockfile.
Using actions/setup-node with npm caching is the cleanest fit here:
cache: npm enables the npm package cache.cache-dependency-path: web/package-lock.json tells GitHub Actions which lockfile to hash.npm ci still installs from the lockfile, but repeated runs can reuse downloaded packages.A broad node_modules cache risks stale contents, and a cache keyed by github.sha is so specific that it provides little reuse across commits.
cache: npm is incomplete for this monorepo because the relevant lockfile is not in the repository root.web/node_modules with only the OS in the key can restore outdated dependencies after lockfile changes.~/.npm by github.sha creates a nearly new cache every commit, so it does not meaningfully reduce repeated install time.Topic: Secure and Optimize Automation
An organization allows a third-party scanning action, but requires that the action’s code must not change between workflow runs unless maintainers review a pull request that updates the workflow file.
name: ci
on: push
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: vendor-labs/license-scan@main
- run: npm test
The team must keep using vendor-labs/license-scan. Which edit best satisfies the policy and minimizes the risk of unreviewed version changes?
Options:
A. Use vendor-labs/license-scan@v2.4.1
B. Use vendor-labs/license-scan@main with read-only permissions
C. Use vendor-labs/license-scan@v2
D. Use vendor-labs/license-scan@4f2c9a1d7b6e8c3f5a0d2e1b9c7f6a4d3e2b1c0f
Best answer: D
Explanation: Pinning the third-party action to a full commit SHA is the only option that fixes the workflow to one exact revision. Branch refs like @main and tag refs like @v2 can change without the workflow file changing, so they do not meet a review-before-update policy.
In GitHub Actions, the uses: value can point to a branch, a tag, or a commit SHA. Branches such as @main and tags such as @v2 are floating references, so the action publisher can move them to different commits without any change in your workflow file. Even a specific version tag is still a tag reference controlled by the publisher.
If the goal is to prevent unreviewed third-party code changes, pin the action to a full commit SHA. That makes the workflow run the same reviewed action revision every time until someone intentionally updates the SHA in a pull request.
Read-only token permissions reduce what the action can do, but they do not stop the referenced action code from changing.
@v2 is still a floating reference and can advance to newer action code without a workflow edit.@v2.4.1 is narrower, but it is still a tag reference rather than an immutable commit identifier.permissions limit GITHUB_TOKEN scope, but they do not pin the third-party action source to one reviewed revision.Topic: Secure and Optimize Automation
A team uses a reusable workflow to build dist/app.tgz and create an artifact attestation. All third-party actions inside package.yml are already pinned to full commit SHAs, and the job uses GitHub-hosted runners. The team wants consumers to rely on the attestation as evidence of a reviewed, immutable build process.
name: release
on:
push:
tags: ['v*']
permissions:
contents: read
attestations: write
id-token: write
jobs:
package:
uses: octo-org/build-templates/.github/workflows/package.yml@main
Which edit best addresses the remaining trust limitation?
Options:
A. Pin the reusable workflow reference to a major version tag
B. Grant contents: write to the workflow
C. Pin the reusable workflow reference to a full commit SHA
D. Add workflow_dispatch as an additional trigger
Best answer: C
Explanation: Artifact attestations prove provenance for the run that produced an artifact, but they do not make a floating workflow reference trustworthy. Because the reusable workflow is called with @main, the build definition can change over time. Pinning it to a full commit SHA makes the attested process immutable and reviewable.
The core issue is workflow trust. An artifact attestation can accurately state which workflow run produced an artifact, but it does not guarantee that the workflow definition itself was fixed or trusted. In this snippet, the reusable workflow is referenced by @main, which is a moving branch reference. That means future runs can produce valid attestations while using different workflow logic.
attestations: write and id-token: write to generate the attestation.The key takeaway is that provenance is only as trustworthy as the workflow, dependencies, and runner environment that produced it.
v1 can still be moved to different commits.Use the GitHub Actions GH-200 Practice Test page for the full IT Mastery route, mixed-topic practice, timed mock exams, explanations, and web/mobile app access.
Try GitHub Actions GH-200 on Web View GitHub Actions GH-200 Practice Test
Read the GitHub Actions GH-200 Cheat Sheet on Tech Exam Lexicon, then return to IT Mastery for timed practice.