Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/codeql/codeql-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
paths-ignore:
- test/fixtures/legacy-compat/**
1 change: 1 addition & 0 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
with:
languages: javascript-typescript
build-mode: none
config-file: ./.github/codeql/codeql-config.yml

- name: Analyze with CodeQL
uses: github/codeql-action/analyze@5595ccaf912efad79be6eef63a5619ff05969be3 # v4.37.6
Expand Down
16 changes: 16 additions & 0 deletions e2e/live-console-errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
const URL_PATTERN = /https?:\/\/[^\s"'<>]+/g;

function referencesGoogleFontsHost(message: string): boolean {
return (message.match(URL_PATTERN) ?? []).some(
candidate => URL.canParse(candidate) && new URL(candidate).hostname === 'fonts.gstatic.com'
);
}

export function isExpectedLiveConsoleError(message: string): boolean {
return (
message.includes('Missing data-repo') ||
referencesGoogleFontsHost(message) ||
message.includes('CORS') ||
message.includes('net::ERR_FAILED')
);
}
9 changes: 2 additions & 7 deletions e2e/widget.live.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
test,
waitForPreviewWidgetResponse,
} from './live-preview-widget';
import { isExpectedLiveConsoleError } from './live-console-errors';

/**
* Live E2E tests for BugDrop widget on a real cross-origin deployment.
Expand Down Expand Up @@ -336,13 +337,7 @@ test.describe('Widget Loading (Live)', () => {
await expect(button).toBeVisible({ timeout: 10_000 });

// No unexpected console errors (filter out CORS font errors and known benign messages)
const unexpectedErrors = errors.filter(
e =>
!e.includes('Missing data-repo') &&
!e.includes('fonts.gstatic.com') &&
!e.includes('CORS') &&
!e.includes('net::ERR_FAILED')
);
const unexpectedErrors = errors.filter(error => !isExpectedLiveConsoleError(error));
expect(unexpectedErrors).toHaveLength(0);
});

Expand Down
6 changes: 6 additions & 0 deletions scripts/check-security-analysis-workflows.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ checkEqual(
checkEqual('codeql.yml: init configuration', codeqlInit?.with, {
languages: 'javascript-typescript',
'build-mode': 'none',
'config-file': './.github/codeql/codeql-config.yml',
});
checkEqual(
'codeql.yml: analyze action',
Expand All @@ -75,6 +76,11 @@ checkEqual('codeql.yml: analyze configuration', codeqlAnalyze?.with, {
category: '/language:javascript-typescript',
});

const codeqlConfig = await readWorkflow('../codeql/codeql-config.yml');
checkEqual('codeql-config.yml: configuration', codeqlConfig, {
'paths-ignore': ['test/fixtures/legacy-compat/**'],
});

const dependencyReview = await readWorkflow('dependency-review.yml');
checkEqual('dependency-review.yml: triggers', dependencyReview.on, {
pull_request: { branches: ['main'] },
Expand Down
23 changes: 23 additions & 0 deletions test/liveConsoleErrors.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { describe, expect, it } from 'vitest';
import { isExpectedLiveConsoleError } from '../e2e/live-console-errors';

describe('live console error filtering', () => {
it.each([
['missing repository configuration', 'Missing data-repo attribute'],
['Google Fonts resource warning', 'Font https://fonts.gstatic.com/s/font.woff2 returned 403'],
['generic CORS failure', 'CORS blocked a cross-origin resource'],
['failed font request', 'GET https://fonts.gstatic.com/s/font.woff2 net::ERR_FAILED'],
])('accepts the known %s error', (_name, message) => {
expect(isExpectedLiveConsoleError(message)).toBe(true);
});

it.each([
['hostname suffix', 'GET https://fonts.gstatic.com.attacker.test/payload.js failed'],
['credentials', 'GET https://fonts.gstatic.com@attacker.test/payload.js failed'],
['subdomain', 'GET https://cdn.fonts.gstatic.com/font.woff2 failed'],
['query parameter', 'GET https://attacker.test/?next=https://fonts.gstatic.com failed'],
['plain-text mention', 'Unexpected script from fonts.gstatic.com executed'],
])('does not hide an unrelated error containing a %s', (_name, message) => {
expect(isExpectedLiveConsoleError(message)).toBe(false);
});
});
19 changes: 15 additions & 4 deletions test/security-analysis-workflows.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,11 @@ trap 'rm -rf "$fixture_root"' EXIT
make_fixture() {
local name=$1
local directory="$fixture_root/$name"
mkdir -p "$directory"
cp "$repo_root/.github/workflows/codeql.yml" "$directory/"
cp "$repo_root/.github/workflows/dependency-review.yml" "$directory/"
printf '%s\n' "$directory"
mkdir -p "$directory/workflows" "$directory/codeql"
cp "$repo_root/.github/workflows/codeql.yml" "$directory/workflows/"
cp "$repo_root/.github/workflows/dependency-review.yml" "$directory/workflows/"
cp "$repo_root/.github/codeql/codeql-config.yml" "$directory/codeql/"
printf '%s\n' "$directory/workflows"
}

expect_failure() {
Expand Down Expand Up @@ -43,6 +44,16 @@ missing_upload=$(make_fixture missing-upload)
perl -0pi -e "s/ security-events: write\n//" "$missing_upload/codeql.yml"
expect_failure "$missing_upload" 'codeql.yml: analyze permissions'

missing_codeql_config=$(make_fixture missing-codeql-config)
perl -0pi -e "s/ config-file: \.\/\.github\/codeql\/codeql-config\.yml\n//" \
"$missing_codeql_config/codeql.yml"
expect_failure "$missing_codeql_config" 'codeql.yml: init configuration'

broad_codeql_exclusion=$(make_fixture broad-codeql-exclusion)
perl -0pi -e 's#test/fixtures/legacy-compat/\*\*#test/fixtures/**#' \
"$fixture_root/broad-codeql-exclusion/codeql/codeql-config.yml"
expect_failure "$broad_codeql_exclusion" 'codeql-config.yml: configuration'

disabled_codeql_job=$(make_fixture disabled-codeql-job)
perl -0pi -e 's/( analyze:\n)/$1 if: false\n/' "$disabled_codeql_job/codeql.yml"
expect_failure "$disabled_codeql_job" 'codeql.yml: analyze job: must not define if'
Expand Down