-
-
Notifications
You must be signed in to change notification settings - Fork 18
ci(frontend): use playwright container, add cache + path filter #1810
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,31 +1,56 @@ | ||
| name: frontend | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main | ||
| # Publish semver tags as releases | ||
| tags: [ '*.*.*' ] | ||
| - main | ||
| tags: | ||
| - '*.*.*' | ||
| paths: | ||
| - 'frontend/**' | ||
| - '.github/workflows/frontend.yml' | ||
| pull_request: | ||
| paths: | ||
| - 'frontend/**' | ||
| - '.github/workflows/frontend.yml' | ||
|
|
||
| concurrency: | ||
| group: frontend-${{ github.ref }} | ||
| cancel-in-progress: true | ||
|
|
||
| defaults: | ||
| run: | ||
| working-directory: frontend | ||
|
|
||
| # TODO: add a lint job once ESLint migration replaces the (already-removed in | ||
| # @angular-devkit/build-angular v20) `tslint` builder that `yarn lint` calls. | ||
|
|
||
| jobs: | ||
| test: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 20 | ||
| container: | ||
| image: mcr.microsoft.com/playwright:v1.58.1-noble | ||
| steps: | ||
| - uses: actions/checkout@v2 | ||
| - uses: actions/setup-node@v3 | ||
| - uses: actions/checkout@v5 | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Disable credential persistence in checkout steps. Line 35 and Line 49 should set Suggested change- - uses: actions/checkout@v5
+ - uses: actions/checkout@v5
+ with:
+ persist-credentials: false
...
- - uses: actions/checkout@v5
+ - uses: actions/checkout@v5
+ with:
+ persist-credentials: falseAlso applies to: 49-49 🧰 Tools🪛 zizmor (1.25.2)[warning] 35-35: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 35-35: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) 🤖 Prompt for AI Agents |
||
| - uses: actions/setup-node@v4 | ||
|
Comment on lines
+35
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
file=".github/workflows/frontend.yml"
echo "== File exists? =="
ls -la "$file" || true
echo
echo "== Show lines 25-70 with numbers =="
nl -ba "$file" | sed -n '25,70p'
echo
echo "== Extract all `uses:` lines =="
rg -n "^\s*-\s*uses:" "$file" || true
echo
echo "== Check for any `permissions:` block =="
rg -n "^\s*permissions:" -S "$file" || true
echo
echo "== Check for checkout credential persistence-related config =="
rg -n "persist-credentials|clean|fetch-depth" "$file" || trueRepository: rocket-admin/rocketadmin Length of output: 266 🏁 Script executed: #!/bin/bash
set -euo pipefail
file=".github/workflows/frontend.yml"
echo "== Show lines 25-70 with numbers (cat -n) =="
cat -n "$file" | sed -n '25,70p'
echo
echo "== Extract all `uses:` lines =="
rg -n "^\s*-\s*uses:" "$file" || true
echo
echo "== Check for any `permissions:` block =="
rg -n "^\s*permissions:" -S "$file" || true
echo
echo "== Check for checkout credential persistence-related config (fetch-depth/persist-credentials) =="
rg -n "persist-credentials|fetch-depth|clean:" "$file" || trueRepository: rocket-admin/rocketadmin Length of output: 1804 Pin GitHub Actions to full commit SHAs.
Suggested change- - uses: actions/checkout@v5
- - uses: actions/setup-node@v4
+ - uses: actions/checkout@<checkout-v5-full-commit-sha>
+ - uses: actions/setup-node@<setup-node-v4-full-commit-sha>
...
- - uses: actions/checkout@v5
- - uses: actions/setup-node@v4
+ - uses: actions/checkout@<checkout-v5-full-commit-sha>
+ - uses: actions/setup-node@<setup-node-v4-full-commit-sha>🧰 Tools🪛 zizmor (1.25.2)[warning] 35-35: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false (artipacked) [error] 35-35: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 36-36: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy) (unpinned-uses) [error] 36-36: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step (cache-poisoning) 🤖 Prompt for AI Agents |
||
| with: | ||
| node-version: '24' | ||
| - run: cd frontend && yarn install | ||
| - name: Install Playwright browsers | ||
| run: cd frontend && yarn playwright install | ||
| - name: run tests | ||
| run: cd frontend && yarn test | ||
| cache: 'yarn' | ||
| cache-dependency-path: frontend/yarn.lock | ||
| - run: yarn install --immutable | ||
| - name: Run unit tests | ||
| run: yarn test:ci | ||
|
|
||
| license: | ||
| runs-on: ubuntu-latest | ||
| timeout-minutes: 10 | ||
| steps: | ||
| - uses: actions/checkout@v2 | ||
| - uses: actions/setup-node@v3 | ||
| - uses: actions/checkout@v5 | ||
| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: '16' | ||
| - uses: extractions/setup-just@v1 | ||
| node-version: '24' | ||
| cache: 'yarn' | ||
| cache-dependency-path: frontend/yarn.lock | ||
| - name: license checker | ||
| run: 'cd frontend && npx license-checker --onlyAllow="MIT;ISC;Python-2.0;Apache-2.0;BSD;MPL;CC;Custom: http://github.com/dscape/statsd-parser;" --excludePrivatePackages' | ||
| run: 'npx --yes license-checker --onlyAllow="MIT;ISC;Python-2.0;Apache-2.0;BSD;MPL;CC;Custom: http://github.com/dscape/statsd-parser;" --excludePrivatePackages' | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,7 @@ import { SignInAuditService } from '../../user-sign-in-audit/sign-in-audit.servi | |
| import { VerifyOtpDS } from '../application/data-structures/verify-otp.ds.js'; | ||
| import { generateGwtToken, IToken } from '../utils/generate-gwt-token.js'; | ||
| import { get2FaScope } from '../utils/is-jwt-scope-need.util.js'; | ||
| import { legacyOtpGuardrails } from '../utils/otp-guardrails.js'; | ||
| import { IOtpLogin } from './user-use-cases.interfaces.js'; | ||
|
|
||
| @Injectable() | ||
|
|
@@ -28,7 +29,11 @@ export class OtpLoginUseCase extends AbstractUseCase<VerifyOtpDS, IToken> implem | |
| if (!foundUser) { | ||
| throw new NotFoundException(Messages.USER_NOT_FOUND); | ||
| } | ||
| const isValid = verifySync({ token: otpToken, secret: foundUser.otpSecretKey }).valid; | ||
| const isValid = verifySync({ | ||
| token: otpToken, | ||
| secret: foundUser.otpSecretKey, | ||
| guardrails: legacyOtpGuardrails, | ||
| }).valid; | ||
|
Comment on lines
+32
to
+36
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
# 1) Inspect otpSecretKey shape/nullability in user entity
fd -i 'user.entity.ts' backend/src/entities | xargs -I{} rg -n -C2 '\botpSecretKey\b' {}
# 2) Compare verifySync handling across OTP use-cases
rg -n -C4 'verifySync\(' \
backend/src/entities/user/use-cases/disable-otp.use.case.ts \
backend/src/entities/user/use-cases/otp-login-use.case.ts \
backend/src/entities/user/use-cases/verify-otp-use.case.tsRepository: rocket-admin/rocketadmin Length of output: 2936 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the surrounding code in otp-login-use.case.ts
sed -n '1,120p' backend/src/entities/user/use-cases/otp-login-use.case.ts | nl -ba | sed -n '1,120p'
echo "----"
# Also inspect a narrower window around the reported lines
sed -n '1,90p' backend/src/entities/user/use-cases/otp-login-use.case.ts | nl -ba | sed -n '15,75p'Repository: rocket-admin/rocketadmin Length of output: 111 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect otp-login use case around verifySync (lines ~20-80) with line numbers
sed -n '1,120p' backend/src/entities/user/use-cases/otp-login-use.case.ts | cat -n
echo "---- narrower window ----"
sed -n '15,80p' backend/src/entities/user/use-cases/otp-login-use.case.ts | cat -nRepository: rocket-admin/rocketadmin Length of output: 5647 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect user entity definition around otpSecretKey
sed -n '60,110p' backend/src/entities/user/user.entity.ts | cat -n
echo "---- verify-otp-use.case.ts ----"
sed -n '1,120p' backend/src/entities/user/use-cases/verify-otp.use.case.ts | cat -n
echo "---- disable-otp.use.case.ts ----"
sed -n '1,120p' backend/src/entities/user/use-cases/disable-otp.use.case.ts | cat -nRepository: rocket-admin/rocketadmin Length of output: 1620 🏁 Script executed: #!/bin/bash
set -euo pipefail
echo "---- verify-otp-use.case.ts (around verifySync) ----"
sed -n '1,140p' backend/src/entities/user/use-cases/verify-otp-use.case.ts | cat -n
echo "---- disable-otp.use.case.ts (around verifySync) ----"
sed -n '1,140p' backend/src/entities/user/use-cases/disable-otp.use.case.ts | cat -nRepository: rocket-admin/rocketadmin Length of output: 5631 🌐 Web query:
💡 Result: The Citations:
Guard nullable
Proposed fix+ if (!foundUser.otpSecretKey) {
+ await this.recordSignInAudit(
+ foundUser.email,
+ userId,
+ SignInStatusEnum.FAILED,
+ ipAddress,
+ userAgent,
+ Messages.LOGIN_DENIED_INVALID_OTP,
+ );
+ throw new BadRequestException(Messages.LOGIN_DENIED_INVALID_OTP);
+ }
- const isValid = verifySync({
- token: otpToken,
- secret: foundUser.otpSecretKey,
- guardrails: legacyOtpGuardrails,
- }).valid;
+ let isValid: boolean;
+ try {
+ isValid = verifySync({
+ token: otpToken,
+ secret: foundUser.otpSecretKey,
+ guardrails: legacyOtpGuardrails,
+ }).valid;
+ } catch {
+ await this.recordSignInAudit(
+ foundUser.email,
+ userId,
+ SignInStatusEnum.FAILED,
+ ipAddress,
+ userAgent,
+ Messages.LOGIN_DENIED_INVALID_OTP,
+ );
+ throw new BadRequestException(Messages.LOGIN_DENIED_INVALID_OTP);
+ }🤖 Prompt for AI Agents |
||
| if (!isValid) { | ||
| await this.recordSignInAudit( | ||
| foundUser.email, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| import { createGuardrails } from 'otplib'; | ||
|
|
||
| // otplib v13 enforces RFC 4226's 128-bit (16-byte) minimum secret length, but | ||
| // users enrolled before the v12 -> v13 upgrade have 10-byte secrets stored | ||
| // (the v12 `authenticator.generateSecret()` default). Relax the guardrail at | ||
| // verify time so those users can still authenticate. New secrets use v13's | ||
| // 20-byte default and are RFC-compliant. | ||
| export const legacyOtpGuardrails = createGuardrails({ MIN_SECRET_BYTES: 10 }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add an explicit top-level
permissionsblock (least privilege).No
permissions:block means default token scopes apply. Tightening scopes here reduces blast radius for both jobs.Suggested change
🤖 Prompt for AI Agents