Free GH-200 practice test

20 questions for the GitHub Actions (GH-200) exam, taken from our 133-question bank and spread across its 5domains by their weighting. No sign-up needed: pick an answer to check it, or open “Show answer & explanation” under any question.

What this test covers

Question 1 · Author and Manage Workflows

A company wants to prevent concurrent deployments to the production environment from the same branch. They want any new run to cancel the currently running one if it exists. Which concurrency configuration achieves this?

Show answer & explanation

Correct answer: B

  • B. concurrency: group: deploy-prod-${{ github.ref }} cancel-in-progress: true

Option B is correct. Using ${{ github.ref }} in the group name scopes the concurrency group per branch, so simultaneous deployments from different branches don't interfere with each other. cancel-in-progress: true ensures the older run is cancelled when a new one starts for the same group. Option D is wrong because cancel-in-progress: false (the default) only queues the new run rather than cancelling the existing one — this prevents concurrent runs but doesn't cancel them. Option C is wrong because ${{ github.run_id }} is unique per run, meaning every run gets its own concurrency group and they never compete — the concurrency setting becomes entirely ineffective. Option A is wrong because cancel-in-progress is not a valid key directly under a job's concurrency field when it is expressed as a scalar string; the correct structure uses an object with group and cancel-in-progress keys. Additionally, placing it only at the job level without scoping to ${{ github.ref }} would conflict across branches.

Question 2 · Author and Manage Workflows

A developer sets an environment variable at the workflow level using env: and tries to override it at the step level with a different value. Which statement is true?

Show answer & explanation

Correct answer: A

  • A. The step-level env: value takes precedence over the workflow-level env: value within that step.

Option A is correct. GitHub Actions environment variables follow a scoping hierarchy: step → job → workflow, where more specific scopes override less specific ones for the same key. A step-level env: definition for a key takes precedence over the same key defined at the job or workflow level, but only for the duration of that step. Option B is wrong because it inverts the precedence order; workflow-level is the least specific scope and is overridden by more specific scopes. Option C is wrong about the conflict resolution direction — it states workflow-level wins on conflict, which is incorrect. Option D is wrong because GitHub Actions silently resolves the conflict using the most specific scope; it does not throw an error.

Question 3 · Author and Manage Workflows

In a workflow, job B must run only after job A completes successfully, and job C must run only after both job A and job B complete successfully. Which configuration correctly expresses these dependencies?

Show answer & explanation

Correct answer: A

  • A. jobB: needs: jobA jobC: needs: [jobA, jobB]

Option A is correct. The needs keyword accepts a single job ID or a list of job IDs, so needs: jobA for job B and needs: [jobA, jobB] for job C correctly model the described dependency graph. Option B is wrong because depends-on is not a valid GitHub Actions keyword — the correct keyword is needs. Option C is wrong because after is not a valid GitHub Actions keyword. Option D is partially correct for job B but wrong for job C: specifying only needs: jobB for job C means it starts as soon as job B finishes and does NOT explicitly require job A; while job A would have already finished (because B needs A), explicitly listing both is the correct and clearer practice — and this is how the exam tests precise knowledge.

Question 4 · Author and Manage Workflows

A developer is debugging a failing workflow and needs to enable both step debug logging and runner diagnostic logging. Which TWO methods will enable this enhanced logging? (Select TWO)

Select 2 answers.

Show answer & explanation

Correct answers: A, B

  • A. Create a repository secret named ACTIONS_RUNNER_DEBUG with the value true.
  • B. Create a repository secret named ACTIONS_STEP_DEBUG with the value true.

Options A and B are correct. GitHub Actions recognizes two special secrets (not variables) that enable enhanced logging: ACTIONS_STEP_DEBUG enables verbose step-level debug messages (e.g., showing each command's inputs and outputs), and ACTIONS_RUNNER_DEBUG enables runner diagnostic logs (e.g., worker and process-level information). Both must be created as repository or organization secrets with the value true. Option E is wrong because adding debug: true to env: is not a recognized GitHub Actions mechanism for enabling debug logging. Option C is wrong because these must be secrets, not variables (the vars context) — using a repository variable named ACTIONS_STEP_DEBUG will not enable debug logging. Option D is wrong because --debug is not a parameter recognized by actions/checkout for enabling GitHub Actions runner debug logs.

Question 5 · Author and Manage Workflows

A team has a reusable workflow defined at .github/workflows/deploy.yml in the same repository. Another workflow wants to call it and pass a secret called DEPLOY_TOKEN without explicitly mapping every secret. Which secrets configuration in the caller workflow achieves this?

Show answer & explanation

Correct answer: B

  • B. jobs: call-deploy: uses: ./.github/workflows/deploy.yml secrets: inherit

Option B is correct. secrets: inherit is the official GitHub Actions syntax that passes all secrets from the caller's context to the reusable workflow automatically, without needing to enumerate each one. Option D is wrong because with: is for input parameters, not secrets, and secrets: all is not valid syntax. Option C is wrong because pass-through: true is not a recognized GitHub Actions construct. Option A is wrong because passing values via env: at the job level does not make them available as secrets inside the called reusable workflow — the called workflow's steps would need to reference them as environment variables, not secrets, and this pattern breaks the expected interface.

Question 6 · Consume and Troubleshoot Workflows

A caller workflow in repository org/app wants to call a reusable workflow located at .github/workflows/build.yml in the same repository. The reusable workflow declares on: workflow_call. Which uses value is correct in the caller workflow?

Show answer & explanation

Correct answer: C

  • C. uses: ./.github/workflows/build.yml

C is correct. A reusable workflow in the same repository is referenced with a relative path that starts with ./, i.e. ./.github/workflows/{filename}, and takes no @ref. A is wrong: the {owner}/{repo}/.github/workflows/{filename} form must end with @{ref} (a SHA, tag or branch), which this value omits. B is wrong: the path must include the .github/workflows/ directory. D is wrong: workflow_call: is a trigger in the called workflow, not a valid prefix for uses.

Question 7 · Consume and Troubleshoot Workflows

An organization enforces a policy that the production GitHub Environment may only be deployed to from the main branch and tags matching v*. A workflow on a hotfix/critical branch references the production environment. What happens when this workflow runs?

Show answer & explanation

Correct answer: C

  • C. The deployment job fails with an error indicating the branch does not match the allowed deployment branches or tag patterns

GitHub enforces deployment branch and tag policies at the environment level. If the triggering ref does not match the configured allowed branches/tags, the deployment job fails — it is not queued, overridable by reviewers, or bypassed. Option B is wrong; reviewers can approve/reject deployments but cannot override deployment branch restrictions. Option A is wrong; GitHub does not merge or promote branches automatically. Option D is wrong; deployment branch restrictions apply equally to workflow runs and are enforced by the GitHub Actions runtime, not just the UI.

Question 8 · Consume and Troubleshoot Workflows

A workflow_dispatch trigger is configured as shown below:

on:
  workflow_dispatch:
    inputs:
      log_level:
        description: 'Logging level'
        required: true
        default: 'info'
        type: choice
        options:
          - debug
          - info
          - warning
          - error

A developer triggers this workflow via the GitHub UI without changing any input. What value will github.event.inputs.log_level hold during the run?

Show answer & explanation

Correct answer: D

  • D. info, because it is the declared default

info is correct because when a workflow_dispatch input has a default value defined, that value is pre-populated in the UI and used if the user does not change it. The input is satisfied by its default, so required: true is not violated. Option A is wrong because the default value is applied automatically. Option C is wrong; while debug is the first listed option, GitHub uses the explicitly declared default field, not the position in the list. Option B is wrong because required: true means a value must be supplied at trigger time, and the default fulfills that requirement.

Question 9 · Author and Maintain Actions

You are writing an action.yml for a Docker container action that must pass two action inputs — 'source-dir' and 'target-dir' — as positional arguments to the container's entrypoint script. Which runs block correctly accomplishes this?

Show answer & explanation

Correct answer: C

  • C. runs: using: 'docker' image: 'Dockerfile' args: - ${{ inputs.source-dir }} - ${{ inputs.target-dir }}

The correct key for passing positional arguments to a Docker action's entrypoint is args, which accepts a list of values. Expression syntax ${{ inputs.<name> }} is valid inside the args array. The env block sets environment variables, not positional arguments — the entrypoint would need to read $SOURCE_DIR and $TARGET_DIR explicitly, not receive them as $1/$2. entrypoint-args is not a valid key in the action.yml schema. command is not a valid key in the Docker runs block for GitHub Actions (it is a Docker Compose concept).

Question 10 · Author and Maintain Actions

A senior engineer is designing a reusable JavaScript action that queries an internal API and must support three behaviors based on caller configuration: (1) accept an API endpoint URL as input, (2) expose the HTTP response status code as an output for downstream steps, and (3) export a step summary to the GitHub Actions workflow summary page. Which combination of @actions/core features and action.yml constructs satisfies ALL three requirements?

Select 2 answers.

Show answer & explanation

Correct answers: A, C

  • A. Declare the endpoint input in action.yml inputs; read it with core.getInput('endpoint'); set the status code with core.setOutput('status-code', responseStatus); write the summary with core.summary.addHeading(...).write().
  • C. Declare the endpoint input in action.yml inputs; read it with core.getInput('endpoint'); set the status code with core.setOutput('status-code', responseStatus); append the summary to $GITHUB_STEP_SUMMARY using fs.appendFileSync.

Both options A and C correctly satisfy all three requirements. (A) uses core.getInput() for the input (recommended), core.setOutput() for the output, and the @actions/core summary API (core.summary) for the step summary — this is the cleanest, fully toolkit-based approach. (C) also correctly uses core.getInput() and core.setOutput(), but writes the summary by appending Markdown directly to the file path in $GITHUB_STEP_SUMMARY — this is a valid alternative approach documented by GitHub. Option B incorrectly uses core.exportVariable() (which sets an env var for downstream steps, not an action output) for the status code. Option D reads the input via process.env.INPUT_ENDPOINT which works but is not the recommended pattern, and while it pairs with valid output/summary methods, it is not the idiomatic approach — however, the key disqualifier here is that it is not incorrect enough to exclude; but B is clearly wrong making A and C the two best correct answers.

Question 11 · Author and Maintain Actions

A team wants to add debug-level logging to their JavaScript action so that additional diagnostic information is only shown when the runner's debug mode is enabled (ACTIONS_STEP_DEBUG=true), without cluttering normal output. Which @actions/core method is designed for this purpose?

Show answer & explanation

Correct answer: C

  • C. core.debug('Diagnostic message here')

core.debug() emits a message that is only visible when the secret ACTIONS_STEP_DEBUG is set to 'true' on the repository, making it ideal for diagnostic output that should not appear in normal runs. core.info() always prints to stdout regardless of debug mode. core.notice() creates a notice-level annotation visible in the workflow summary and UI, unrelated to debug verbosity. core.verbose() does not exist in the @actions/core package — it is a common misconception based on other logging libraries.

Question 12 · Author and Maintain Actions

A platform engineer wants to configure a GitHub Actions workflow to authenticate to Google Cloud using OIDC (OpenID Connect) without storing a service account key. Which TWO of the following are required for this to work correctly?

Select 2 answers.

Show answer & explanation

Correct answers: C, E

  • C. A Google Cloud Workload Identity Pool must be configured to trust the GitHub OIDC issuer (https://token.actions.githubusercontent.com).
  • E. The workflow job must set id-token: write in its permissions block.

Two things are required: (1) The job must declare id-token: write permission so the GitHub Actions runner is authorized to request a JWT from GitHub's OIDC provider — without this the token request fails. (2) On the cloud provider side, a trust relationship must be established (a Workload Identity Pool in GCP) that accepts tokens from GitHub's OIDC issuer URL. OIDC tokens are fully supported on GitHub-hosted runners — self-hosted runners are not required. OIDC works for both public and private repositories. There is no 'oidc' OAuth scope for GitHub Apps relevant to this flow; the permission is controlled at the workflow job level.

Question 13 · Manage GitHub Actions for the Enterprise

A platform engineering team manages a self-hosted runner fleet for multiple organizations within a GitHub Enterprise. They want a subset of high-memory runners to be accessible only to the data-engineering and ml-platform organizations, while remaining hidden from all other organizations. What is the correct approach?

Show answer & explanation

Correct answer: C

  • C. Create a runner group at the enterprise level, assign the high-memory runners to it, and set the group's organization access to only data-engineering and ml-platform

Option C is correct because enterprise-level runner groups are specifically designed to control which organizations can access a given set of runners. By creating an enterprise runner group and limiting its access to only the two specified organizations, the runners are invisible and inaccessible to all other organizations. Option A is wrong because the default runner group is accessible to all organizations by default, and runner labels alone do not enforce access control—any org could still reference the label. Option B is wrong because a self-hosted runner can only be registered in one location at a time; registering the same runner in two org-level groups simultaneously is not supported. Option D is wrong because labels are a targeting mechanism, not an access-control mechanism; any organization with access to the runner could use the label.

Question 14 · Manage GitHub Actions for the Enterprise

An enterprise administrator is reviewing GitHub Actions billing for an organization on the GitHub Team plan. A developer claims that macOS runner minutes are being exhausted much faster than Linux runner minutes despite similar job counts. Which statement best explains this behavior?

Show answer & explanation

Correct answer: B

  • B. macOS runner minutes are multiplied by a factor of 10 compared to Linux runner minutes, causing faster consumption of the included minute allowance

Option B is correct because GitHub applies minute multipliers to non-Linux runners: macOS jobs consume minutes at 10× the rate of Linux jobs against the plan's included minute allowance, causing rapid depletion even with fewer jobs. Option D is wrong because it inverts the relationship — macOS has a higher multiplier (more expensive), not lower. Option A is wrong because macOS runners are included in Team plan minutes but with the multiplier; they are not billed at a flat rate per job. Option C is wrong because Actions minutes and GitHub Packages storage are tracked separately; macOS minutes draw from the Actions minute allowance, not a shared Packages quota.

Question 15 · Manage GitHub Actions for the Enterprise

An organization on GitHub's Team plan has 10 developers. At the end of the billing month, the Actions usage dashboard shows that the organization has consumed 3,200 minutes using Ubuntu GitHub-hosted runners. How many of those minutes are billable?

Show answer & explanation

Correct answer: B

  • B. 200 minutes, because the Team plan includes 3,000 free minutes per month and Ubuntu runners are billed at a 1× multiplier

Option B is correct. GitHub's Team plan includes 3,000 free Actions minutes per month, and Linux (Ubuntu) GitHub-hosted runners consume minutes at a 1× multiplier (i.e., 1 minute of run time = 1 minute deducted). The organization used 3,200 minutes, so 3,200 − 3,000 = 200 minutes are billable. Option D is wrong because the Team plan does not offer unlimited minutes; only Enterprise Cloud with certain agreements might have different terms. Option A is wrong because the 2× multiplier applies to Windows runners, not Ubuntu/Linux runners. Option C is wrong because free included minutes apply to GitHub-hosted runners, not self-hosted runners (self-hosted runners are always free with regard to per-minute charges).

Question 16 · Manage GitHub Actions for the Enterprise

An enterprise administrator is using the audit log to investigate unauthorized changes to Actions secrets within an organization. Which audit log event action would indicate that an organization-level encrypted secret was updated?

Show answer & explanation

Correct answer: D

  • D. org.secret_updated

Option D is correct because GitHub's audit log uses the event action org.secret_updated to record changes to organization-level Actions encrypted secrets, following the {resource}.{action} naming convention for org-scoped events. Option A is wrong because secret_scanning.alert_resolved relates to secret scanning alerts (e.g., leaked credentials detected in code), not to changes to encrypted secrets stored in Actions settings. Option B is wrong because org.actions_secret_changed is not a real audit log event name; GitHub does not use the format actions_secret_changed for this event. Option C is wrong because action.secret_changed is also not a valid audit log event; action is not the resource namespace used for secrets in GitHub's audit log schema.

Question 17 · Manage GitHub Actions for the Enterprise

An organization administrator wants to enforce a specific security-scanning workflow across all repositories in their organization using 'required workflows'. Which of the following statements about required workflows are correct? (Select TWO)

Select 2 answers.

Show answer & explanation

Correct answers: C, D

  • C. A required workflow will block a pull request from merging if it fails or has not run
  • D. Required workflows run in addition to, not instead of, repository-level workflows

Option C is correct because required workflows are enforced as required status checks — if they fail or do not run, pull requests cannot be merged, which is the primary enforcement mechanism. Option D is correct because required workflows are additive; they run alongside any workflows already defined in target repositories and do not replace them. Option A is wrong because required workflows must be defined in a designated repository that the organization policy points to; this does not need to be named .github specifically, but it is a single source repo — the key error is implying 'any repository' works without configuration. Option B is wrong because required workflows can be stored in any designated repository within the organization, not exclusively one named .github. Option E is wrong because required workflows do not depend on branch protection rules being pre-configured; they are a separate organization-level enforcement mechanism. Option F is wrong because required workflow minutes are charged to the repository where the workflow runs (the target repo), but the distinction described is a distractor — the source repository designation does not affect billing in the way implied.

Question 18 · Secure and Optimize Automation

Your team uses actions/cache for a build directory in a public repository. A reviewer warns about cache poisoning from pull requests. Which statement best describes the actual exposure and appropriate mitigation?

Show answer & explanation

Correct answer: D

  • D. A pull_request workflow can write a cache scoped to its PR ref, which cannot be read by the default branch; risk arises mainly when workflows restore caches across trust boundaries or use pull_request_target, so avoid caching build outputs in privileged workflows and include a trusted lockfile hash in the key

Correct: cache scoping means a PR branch cache is not readable from the default branch, so the practical danger is privileged workflows (notably pull_request_target, or jobs that restore caches a fork could have influenced) consuming untrusted cached content; mitigations include not caching executable build output in privileged jobs and deriving keys from trusted, content-addressed inputs. Caches do not flow upward from PR refs to the default branch. Caches are not cryptographically signed. fail-on-cache-miss only controls whether a miss fails the step; it does not restrict which refs a cache came from.

Question 19 · Secure and Optimize Automation

A self-hosted runner is registered at the organization level and made available to all repositories, including public ones. Which risk should be raised first?

Show answer & explanation

Correct answer: D

  • D. Workflows from public-repository forks could run untrusted code on a persistent machine that is not cleaned between jobs, enabling credential theft and lateral movement

Correct: GitHub explicitly recommends against self-hosted runners on public repositories because forked-PR workflows can execute arbitrary code on a non-ephemeral host, persisting malware, harvesting tokens or attacking the network. Self-hosted runners do receive the GITHUB_TOKEN normally. Self-hosted runner usage is not billed as Actions minutes at all. Self-hosted runners can use the hosted cache service.

Question 20 · Secure and Optimize Automation

Your monorepo CI takes 40 minutes. Analysis shows most time is spent re-downloading npm dependencies in each of 12 matrix jobs, and the jobs run sequentially because each needs the previous one. Which two changes will most reduce wall-clock time and billable minutes? (Select TWO.)

Select 2 answers.

Show answer & explanation

Correct answers: A, C

  • A. Add dependency caching (for example actions/setup-node with cache: npm) keyed on the lockfile hash
  • C. Remove the unnecessary needs dependencies so the independent matrix jobs run in parallel

Correct: caching keyed on the lockfile hash eliminates repeated dependency downloads across jobs and runs, and removing artificial needs edges lets independent jobs execute concurrently, cutting wall-clock time. Doubling the matrix increases job-startup overhead and billed minutes without addressing the download cost. Long artifact retention increases storage cost and does not speed up builds — artifacts are not a substitute for a dependency cache. Collapsing the matrix into one serial job removes parallelism and makes the run slower.

Pick an answer on each question to check it. 20 questions in this test.

113 more GH-200 questions

Sign up free to start practising, or subscribe (from $4.97/mo) for the full 133-question bank, flashcards and timed mock exams.

GitHub Actions course overview and study guides →