Skip to content

fix: ground repository CI docs in checked-out config#396

Open
Ben Younes (ousamabenyounes) wants to merge 2 commits into
langchain-ai:mainfrom
ousamabenyounes:fix/issue-389-repo-ci-grounding
Open

fix: ground repository CI docs in checked-out config#396
Ben Younes (ousamabenyounes) wants to merge 2 commits into
langchain-ai:mainfrom
ousamabenyounes:fix/issue-389-repo-ci-grounding

Conversation

@ousamabenyounes

@ousamabenyounes Ben Younes (ousamabenyounes) commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Summary

  • preload checked-out repository CI configuration into the run context for repository init/update prompts
  • include GitHub Actions, GitLab CI, and Bitbucket Pipelines files as deterministic source evidence before the model writes docs
  • cap the injected CI context at 64 KiB with an explicit truncation marker, so large workflow sets do not silently bloat every prompt
  • reject symlinked CI config paths and workflow directories before reading them, preventing prompt exfiltration through .gitlab-ci.yml, bitbucket-pipelines.yml, or .github/workflows
  • keep repository-mode prompt guidance that OpenWiki defaults/examples must not override the host repo's actual workflow/config files
  • add regression coverage for prompt boundaries, GitHub/GitLab/Bitbucket CI context, no-CI repos, local-wiki exclusion, truncation, and symlink exfiltration

Fixes #389

Why this is not prompt-only

The prompt instruction is now a secondary guard. The runtime also reads the checked-out CI files before the LLM run and injects their contents into the user prompt as repository automation context, so the agent receives the repo's actual workflow provider/model values without needing to decide to inspect those files first.

Security note

Direct root CI config paths and the .github/workflows directory are checked with lstat() before reading, so symlinks are ignored. Normal files and workflow directories are also checked with realpath() to ensure their resolved path remains inside the repository root before their contents can be injected into the LLM prompt.

Test verification (RED → GREEN)

RED on upstream-base behavior with the prompt regression test:

FAIL  test/prompt.test.ts > createSystemPrompt repository evidence grounding > grounds repository update CI documentation in checked-out workflow files
AssertionError: expected 'You are OpenWiki, an expert technical…' to contain 'When documenting this repository\'s C…'
Test Files  1 failed (1)
Tests  1 failed | 1 passed (2)

RED with the deterministic CI-context patch reverted, leaving only the earlier prompt-only change:

FAIL  test/repository-ci-context.test.ts > repository CI context > injects checked-out workflow configuration into repository update prompts
AssertionError: the given combination of arguments (undefined and string) is invalid for this assertion.
Test Files  1 failed (1)
Tests  1 failed (1)

RED with only the CI-context cap/lookup code reverted while keeping the expanded tests:

FAIL  test/repository-ci-context.test.ts > repository CI context > truncates oversized repository CI context with an explicit byte count
AssertionError: expected 'Repository automation context (checke…' to contain '[...truncated, '
Test Files  1 failed (1)
Tests  1 failed | 4 passed (5)

RED for Corridor's symlink exfiltration finding before the lstat() fix:

FAIL  test/repository-ci-context.test.ts > repository CI context > does not follow symlinks for direct CI config paths
AssertionError: expected 'Repository automation context (checke…' not to contain 'SECRET_TOKEN=do-not-leak'
Test Files  1 failed (1)
Tests  1 failed | 5 passed (6)

RED for Corridor's symlinked GitHub workflows directory finding before the directory lstat()/realpath() fix:

FAIL  test/repository-ci-context.test.ts > repository CI context > does not follow symlinked GitHub workflows directories
AssertionError: expected 'Repository automation context (checke…' not to contain 'SECRET_TOKEN=do-not-leak'
Test Files  1 failed (1)
Tests  1 failed | 6 skipped (7)

GREEN with the full fix:

pnpm exec vitest run test/prompt.test.ts test/repository-ci-context.test.ts
Test Files  2 passed (2)
Tests  24 passed (24)

Full local verification:

pnpm run typecheck
# passed

pnpm run lint:check
# passed

pnpm run format:check
All matched files use Prettier code style!

pnpm run test
Test Files  51 passed (51)
Tests  613 passed (613)

pnpm run build
# passed

OPENWIKI_DEV=1 node dist/cli.js code --dry-run --init
# passed; dry run writes no files or metadata

@ousamabenyounes
Ben Younes (ousamabenyounes) force-pushed the fix/issue-389-repo-ci-grounding branch 2 times, most recently from ed7ddb8 to 90ddbef Compare July 19, 2026 12:32

@corridor-security corridor-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A symlink traversal vulnerability in the CI context loader allows a malicious repository to exfiltrate arbitrary local files by placing a symlink named .gitlab-ci.yml or bitbucket-pipelines.yml pointing to a sensitive path; the symlink target is read and injected into the LLM prompt.

Comment thread src/agent/utils.ts Outdated
@ousamabenyounes
Ben Younes (ousamabenyounes) force-pushed the fix/issue-389-repo-ci-grounding branch from 90ddbef to 44129a5 Compare July 19, 2026 12:47
@ousamabenyounes

Copy link
Copy Markdown
Contributor Author

Thanks, this was a valid finding. I fixed it in the latest push by switching direct CI path discovery from stat() to lstat(), ignoring symlinks before any readFile() call, and adding a realpath() containment check for normal files. I also added a regression test that creates a .gitlab-ci.yml symlink to a temp secret outside the repo and verifies the secret never appears in ciSummary.

@ousamabenyounes
Ben Younes (ousamabenyounes) force-pushed the fix/issue-389-repo-ci-grounding branch from 44129a5 to 150cfb3 Compare July 23, 2026 22:20

@corridor-security corridor-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The .github/workflows directory is read without an lstat check on the directory itself, allowing a repository-supplied symlink at that path to redirect readdir() outside the repo and expose arbitrary YAML files to the LLM prompt; the protections applied to direct CI files (.gitlab-ci.yml, bitbucket-pipelines.yml) are not extended to this code path.

Comment thread src/agent/utils.ts
@ousamabenyounes

Copy link
Copy Markdown
Contributor Author

Rebased on latest main and addressed the Corridor finding about symlinked .github/workflows directories.\n\nValidation after the fix:\n- Corridor Review: passing\n- pnpm run format:check: passing\n- pnpm run lint:check: passing\n- pnpm run typecheck: passing\n- pnpm test: 51 files passed, 613 tests passed\n- pnpm run build: passing\n- OPENWIKI_DEV=1 node dist/cli.js code --dry-run --init: passing

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Update agent rewrites the host repo's CI docs with OpenWiki's own recommended defaults instead of the repo's actual workflow config (since 0.1.2)

1 participant