test+ci: unbreak master — symlink-walker probe files + OSV caller permissions (#2926)

* test: symlink-walker tests use a non-metafile probe (README now skipped by design, #2315)

The import walker deliberately skips README/metafiles since #2315 (closing
#345); the symlink-hardening tests used README.md as their probe file and
went red on the intersection. Probe with notes.md instead; test intent
(cycle hardening + strategy filter) unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* ci: grant security-events write to the OSV caller job — reusable workflow requires it at startup

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Sinabina <sinabina@Sinabinas-MacBook-Pro-4.local>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Time Attakc
2026-07-17 12:10:47 -07:00
committed by GitHub
co-authored by Sinabina Claude Fable 5
parent a31f16f471
commit b075a9c8d4
2 changed files with 9 additions and 5 deletions
+4
View File
@@ -24,6 +24,10 @@ jobs:
permissions:
actions: read
contents: read
# Required by the reusable workflow's own top-level permissions block —
# GitHub validates the caller grants a superset AT STARTUP, even with
# upload-sarif: false (nothing is actually uploaded; see #2117 upstream).
security-events: write
uses: google/osv-scanner-action/.github/workflows/osv-scanner-reusable.yml@9a498708959aeaef5ef730655706c5a1df1edbc2 # v2.3.8
with:
upload-sarif: false
+5 -5
View File
@@ -34,7 +34,7 @@ afterEach(() => {
describe('collectSyncableFiles symlink + cycle hardening', () => {
test('1. self-referencing symlink does not loop', async () => {
await withEnv({ GBRAIN_EMBEDDING_MULTIMODAL: undefined }, () => {
writeFileSync(join(tmp, 'README.md'), '# top\n');
writeFileSync(join(tmp, 'notes.md'), '# top\n');
// Symlink "loop" inside tempdir pointing back to itself.
symlinkSync(tmp, join(tmp, 'loop'));
@@ -43,7 +43,7 @@ describe('collectSyncableFiles symlink + cycle hardening', () => {
const ms = Date.now() - t0;
expect(ms).toBeLessThan(1000); // would hang if walker followed the loop
expect(files).toContain(join(tmp, 'README.md'));
expect(files).toContain(join(tmp, 'notes.md'));
expect(files.every(f => !f.includes('/loop/'))).toBe(true);
});
});
@@ -88,7 +88,7 @@ describe('collectSyncableFiles symlink + cycle hardening', () => {
test('4. strategy filter admits the right files', async () => {
await withEnv({ GBRAIN_EMBEDDING_MULTIMODAL: undefined }, () => {
writeFileSync(join(tmp, 'README.md'), '# r\n');
writeFileSync(join(tmp, 'notes.md'), '# r\n');
writeFileSync(join(tmp, 'foo.ts'), '// f\n');
writeFileSync(join(tmp, 'bar.py'), '# b\n');
@@ -97,8 +97,8 @@ describe('collectSyncableFiles symlink + cycle hardening', () => {
const auto = collectSyncableFiles(tmp, { strategy: 'auto' });
expect(code.map(f => f.split('/').pop()).sort()).toEqual(['bar.py', 'foo.ts']);
expect(markdown.map(f => f.split('/').pop())).toEqual(['README.md']);
expect(auto.map(f => f.split('/').pop()).sort()).toEqual(['README.md', 'bar.py', 'foo.ts']);
expect(markdown.map(f => f.split('/').pop())).toEqual(['notes.md']);
expect(auto.map(f => f.split('/').pop()).sort()).toEqual(['bar.py', 'foo.ts', 'notes.md']);
});
});