Turn the regression into a CI gate
Run the same security tests for changes with a read-only CI token.
Need to set up your terminal or tools? · Look up a term
YOUR TASK · LOCAL MACHINE
Prove the tests detect a regression, then restore the working fix. Optionally run the same check in GitHub Actions.
Node.js 24 and the fixed files from lab 02. A GitHub account is not needed for the exercise below.
You have seen the tests fail without the guard and pass again after restoring it.
Do the exercise on your computer. This page provides instructions and saves completion marks; it does not run commands or check your files.
Follow these steps
Terminal · extracted starter folder
Confirm the fixed version passes
TERMINALnode verify-lab.mjs fixed
Do this exercise in your local learning copy, with no real data.
Check before continuingAll 5 tests pass. If they do not, finish lab 02 first.
Text editor · app.mjs
Temporarily remove only the ownership guard
Find the three-line block you added in lab 02. Remove only that block and save. Leave the original return and the other checks in place.
REMOVE THIS BLOCK TEMPORARILYif (record.owner !== user) { return { status: 403, body: { error: 'Forbidden' } }; }Check before continuingYour learning app temporarily has its original ownership bug. No tests have been edited.
Terminal · same folder
Confirm the regression is caught
TERMINALnode verify-lab.mjs baseline
This failing result is the evidence you want: the tests reject the broken version.
Check before continuing3 tests pass and 2 fail, just as they did before the fix in lab 02.
Text editor, then terminal
Restore the guard and rerun the tests
Put the ownership guard back in exactly the same position. Save
app.mjs, then rerun:TERMINALnode verify-lab.mjs fixed
Leave your app in this passing state before moving on.
Check before continuingAll 5 tests pass again. The local exercise is complete.
Optional: run this check in GitHub Actions
You need your own GitHub lab repository. This optional step uploads the exercise files to that repository; it does not publish the website.
- Keep the fixed
app.mjsandsecurity.test.mjsat the repository root. - Create
.github, thenworkflowsinside it, and place the suppliedsecurity.ymlthere. - Commit and push those files to your lab repository using your normal Git workflow.
- Open the repository on GitHub. Choose Actions → Security regression tests, open the latest run, and select the security-tests job.
- The test step should show five passes. If no run appears, check the workflow path and whether Actions is enabled.
This website does not create the repository, push files, or configure required merge checks. The local exercise above is enough to continue.
Why it works & help if you get stuck
THE CI HANDOFF
Same test command. A different place to run it.
The ZIP includes security.yml. Put it at this path in a lab repository you control. Keep the two JavaScript files at the repository root.
your-lab/
app.mjs
security.test.mjs
.github/
workflows/
security.yml- Read-only permissions: contents: read is enough to fetch the repository for this job.
- No saved checkout credential: persist-credentials: false avoids leaving the token available to later git commands.
- No dependency install: the fixture uses Node’s standard library, so there is no lockfile or npm install step.
- Bounded execution: timeout-minutes: 5 keeps an accidentally stuck job from running indefinitely.
Verify a hosted run yourself
After committing the files to your own lab repository, open Actions → Security regression tests → security-tests. Confirm the test step reports five passes. In a separate branch, remove the ownership guard and open a pull request: the same step should fail. Restore the guard and confirm the next run passes.
If you want this result to block merges, configure a repository ruleset requiring the security-tests check. Confirm it on a test pull request. This website does not configure the repository.
The supplied YAML passed actionlint 1.7.12, and its test command passed locally on Windows and in the Linux container build. No hosted GitHub Actions run or repository ruleset was tested because no lab repository is connected.
IF YOUR RESULT IS DIFFERENT
Common wrong turns
| What happened | Why it matters | What to do instead |
|---|---|---|
| No run appears. | The workflow may be in the wrong path, uncommitted, or Actions may be disabled for that repository. | Check .github/workflows/security.yml and the repository’s Actions settings. |
| A green check but anyone can merge a failing change. | A workflow result is not a required merge policy by itself. | Require the matching check in repository rules. |
| A missing lockfile error. | Caching or an install step was added for a fixture with no packages. | Use the supplied workflow, which disables package-manager caching. |
Need to set up your terminal or tools? · Look up a term
YOUR TASK · DOCKER
Prove that the containerized tests reject a regression, then restore the working fix.
Docker and the fixed files from lab 02. The local regression exercise runs in a temporary container. GitHub is optional.
You have seen the tests fail without the guard and pass again after restoring it.
Do the exercise on your computer. This page provides instructions and saves completion marks; it does not run commands or check your files.
Follow these steps
Terminal · extracted starter folder
Confirm the fixed version passes
TERMINALdocker run --rm --mount "type=bind,source=.,target=/app,readonly" -w /app node:24-alpine node verify-lab.mjs fixed
Do this exercise in your local learning copy, with no real data.
Check before continuingAll 5 tests pass. If they do not, finish lab 02 first.
Text editor · app.mjs
Temporarily remove only the ownership guard
Find the three-line block you added in lab 02. Remove only that block and save. Leave the original return and the other checks in place.
REMOVE THIS BLOCK TEMPORARILYif (record.owner !== user) { return { status: 403, body: { error: 'Forbidden' } }; }Check before continuingYour learning app temporarily has its original ownership bug. No tests have been edited.
Terminal · same folder
Confirm the regression is caught
TERMINALdocker run --rm --mount "type=bind,source=.,target=/app,readonly" -w /app node:24-alpine node verify-lab.mjs baseline
This failing result is the evidence you want: the tests reject the broken version.
Check before continuing3 tests pass and 2 fail, just as they did before the fix in lab 02.
Text editor, then terminal
Restore the guard and rerun the tests
Put the ownership guard back in exactly the same position. Save
app.mjs, then rerun:TERMINALdocker run --rm --mount "type=bind,source=.,target=/app,readonly" -w /app node:24-alpine node verify-lab.mjs fixed
Leave your app in this passing state before moving on.
Check before continuingAll 5 tests pass again. The local exercise is complete.
Optional: run this check in GitHub Actions
You need your own GitHub lab repository. This optional step uploads the exercise files to that repository; it does not publish the website.
- Keep the fixed
app.mjsandsecurity.test.mjsat the repository root. - Create
.github, thenworkflowsinside it, and place the suppliedsecurity.ymlthere. - Commit and push those files to your lab repository using your normal Git workflow.
- Open the repository on GitHub. Choose Actions → Security regression tests, open the latest run, and select the security-tests job.
- The test step should show five passes. If no run appears, check the workflow path and whether Actions is enabled.
This website does not create the repository, push files, or configure required merge checks. The local exercise above is enough to continue.
TRY WITHOUT COPYING · OPTIONAL
Predict before running
Why is a passing test run alone weaker evidence than seeing the same tests fail with the bug and pass with the fix?
Compare your reasoning
A test that never fails may not exercise the bug. Deliberately breaking this learning fixture demonstrates that the checks can detect this particular regression.
Explain your answer aloud or write a sentence before opening the explanation. This does not change your completion record.
A QUICK CHECK
Does a failing Actions job automatically prevent all merges?
Compare with the solution +
Use pull_request and push triggers, contents: read, persist-credentials: false, and a bounded job timeout. Keep deployment permissions out of this test job. Require the check in repository rules when ready.GitHub Node.js workflows ↗
Done with this one?
Marking complete is your own record.
Confirm both results before marking this lab complete.