Skip to content

Phase 1 kickoff: parser core + isolation - #21

Merged
ARCoder181105 merged 17 commits into
mainfrom
phase-1/parser-core-and-isolation
Jul 26, 2026
Merged

Phase 1 kickoff: parser core + isolation#21
ARCoder181105 merged 17 commits into
mainfrom
phase-1/parser-core-and-isolation

Conversation

@ARCoder181105

@ARCoder181105 ARCoder181105 commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Phase 1: Parser core + isolation. Implement TypeScript extraction, JSON IR output, golden tests, isolated CI workflow, and update docs.

Summary by CodeRabbit

  • New Features
    • Parser CLI now exports the extracted repo-wide TypeScript graph as indented JSON or a compact summary (--format / --out).
  • Bug Fixes
    • Hardened repository traversal and parsing inputs (symlink rejection, stricter path handling, binary detection, and enforced file/path caps).
  • Documentation
    • Added Phase 1 planning/acceptance checklists, updated security guidance, and refined the call-resolution naming rules in the parsing strategy.
  • Chores
    • Updated CI workflows (Go/Node) and enhanced Docker build/runtime and golden/fixture-based extraction tests.

Starts Phase 1 (parser core + isolation) on top of the Phase 0 scaffold.
Adds docs/PHASE1_TASKS.md as the working task list for the phase:
ten ordered tasks with acceptance criteria, open decisions to confirm,
and a Definition of Done checklist.

Documentation only; implementation follows in subsequent commits.
@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Phase 1 adds TypeScript tree-sitter extraction into an IR graph, CLI JSON and summary output, stronger traversal and container controls, golden fixtures, separated CI workflows, and synchronized product and implementation documentation.

Changes

Parser Phase 1

Layer / File(s) Summary
TypeScript extraction pipeline
services/parser/internal/ir/*, services/parser/internal/ts/*, services/parser/queries/*
Compiles embedded queries and extracts files, functions, calls, imports, qualified names, and overload indices into ir.Graph.
Extraction fixtures and golden validation
services/parser/internal/ts/*_test.go, services/parser/testdata/*
Adds query tests, TypeScript fixtures, expected graph JSON, and golden comparison coverage.
Traversal isolation, CLI output, and runtime
services/parser/internal/security/path.go, services/parser/cmd/parser/main.go, services/parser/Dockerfile, .gitignore
Rejects symlinks and escaped paths, skips oversized or binary files, adds JSON/summary output, and runs the parser as UID/GID 1000.
Go and Node CI workflows
.github/workflows/*, Makefile
Separates Go and Node checks and adds parser linting, race tests, builds, sample execution, and migration validation.
Phase planning and product contracts
PRD.md, TASKLIST.md, docs/*, CLAUDE.md
Adds product, Phase 1, handoff, status, parsing, and security documentation covering extraction, isolation, naming, validation, and deferred work.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI
  participant Extract
  participant TreeSitter
  participant Graph
  CLI->>Extract: Request repository extraction
  Extract->>TreeSitter: Parse TypeScript and run queries
  TreeSitter-->>Extract: Return declaration and call captures
  Extract->>Graph: Populate files, functions, calls, and imports
  Graph-->>CLI: Emit JSON or summary output
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.29% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main Phase 1 parser and isolation work without noise.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@ARCoder181105
ARCoder181105 marked this pull request as draft July 22, 2026 04:52
@ARCoder181105
ARCoder181105 requested a review from Copilot July 26, 2026 12:27
@ARCoder181105
ARCoder181105 marked this pull request as ready for review July 26, 2026 12:27

Copilot AI 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.

Pull request overview

This PR kicks off Phase 1 (parser core + isolation) by adding/expanding the Phase 1 execution plan and implementing a first end-to-end TypeScript extraction pipeline (tree-sitter queries → IR graph) with initial fixtures, golden outputs, and CI/workflow updates.

Changes:

  • Added Phase 1 planning/contract docs (PRD, task lists, parsing strategy updates, model handoff notes).
  • Implemented initial TypeScript query loading + extraction to ir.Graph, plus golden/fixture testdata.
  • Updated parser runtime/packaging (CLI output flags, Dockerfile) and split CI workflows (Go vs Node).

Reviewed changes

Copilot reviewed 29 out of 29 changed files in this pull request and generated 12 comments.

Show a summary per file
File Description
TASKLIST.md Phase 1 chunk-by-chunk execution checklist and acceptance criteria
services/parser/testdata/sample/arrows.ts Adds arrow/function-expression and overload examples to sample fixtures
services/parser/testdata/nested/repo.ts Adds nesting/class method fixture for qualified-name behavior
services/parser/testdata/golden/repo.ts Adds comprehensive “golden” TS fixture covering defs/calls/imports
services/parser/testdata/golden/package.json Adds minimal non-TS file to golden fixture repo
services/parser/testdata/golden/imports.ts Adds golden import forms fixture
services/parser/testdata/golden/extract_expected.json Stores expected extraction output for golden test
services/parser/testdata/golden/extract_actual.json Stores “actual” extraction output (currently committed)
services/parser/testdata/golden/calls.ts Adds golden calls fixture
services/parser/testdata/calls/repo.ts Adds calls fixture including module-level call
services/parser/queries/typescript.scm Extends tree-sitter queries (export source field + var-declarator functions)
services/parser/queries/embed.go Embeds .scm query file into the binary
services/parser/out.json Committed example output JSON (generated artifact)
services/parser/internal/ts/scope.go Adds qualified-name scope walker for TS AST nodes
services/parser/internal/ts/queries.go Adds query compilation/loading helpers
services/parser/internal/ts/queries_test.go Tests query compilation against TS grammar
services/parser/internal/ts/extract.go Implements extraction of Functions/Calls/Imports into ir.Graph
services/parser/internal/ts/extract_test.go Golden test for extraction output
services/parser/internal/security/path.go Tightens walk behavior (symlink guard + oversize logging/handling)
services/parser/internal/ir/ir.go Updates ir.Import to store multiple symbols
services/parser/Dockerfile Updates build/runtime images and non-root runtime user
services/parser/cmd/parser/main.go Adds JSON output + summary format + --out flag
PRD.md Adds product requirements + phase plan and locked decisions
docs/PHASE1_TASKS.md Adds Phase 1 task plan and acceptance criteria
docs/PARSING_STRATEGY.md Documents naming rules / resolution framing updates
docs/NEXT_MODEL_HANDOFF.md Adds one-shot handoff context for future model sessions
CLAUDE.md Updates phase status checklist
.github/workflows/node-ci.yml Adds dedicated Node CI workflow
.github/workflows/go-ci.yml Renames Go CI and removes Node steps from Go workflow

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread services/parser/Dockerfile Outdated
# Multi-stage build. Runtime runs with --network none, read-only mount, dropped
# caps, non-root (docs/SECURITY.md). CGO is required for tree-sitter.
FROM golang:1.22 AS build
FROM golang:1.24-alpine AS build
Comment on lines +107 to +115
graph.Functions = append(graph.Functions, ir.Function{
PackagePath: pkgPath,
Name: funcName,
QualifiedName: qualifiedName(*declNode, src, funcName),
OverloadIndex: 0,
StartLine: startLine,
EndLine: endLine,
Source: source,
})
Comment thread services/parser/internal/ts/extract.go Outdated
Comment on lines +63 to +67
qs, err := loadQueries(lang)
if err != nil {
tree.Close()
return ir.Graph{}, fmt.Errorf("loadQueries: %w", err)
}
Comment on lines +121 to +122
cursor = tree_sitter.NewQueryCursor()
callMatches := cursor.Matches(qs.call, tree.RootNode(), src)
Comment on lines +184 to +185
cursor = tree_sitter.NewQueryCursor()
impMatches := cursor.Matches(qs.imp, tree.RootNode(), src)
Comment on lines +29 to +32
actualFile := "../../testdata/golden/extract_actual.json"
if err := os.WriteFile(actualFile, actualData, 0644); err != nil {
t.Fatalf("WriteFile failed: %v", err)
}
Comment thread services/parser/out.json Outdated
Comment on lines +1 to +5
{
"Files": [
{
"Path": "calls.ts",
"Language": "typescript"
Comment on lines +1 to +5
{
"Files": [
{
"Path": "calls.ts",
"Language": "typescript"
Comment thread CLAUDE.md
Comment on lines +11 to +15
- [x] Phase 0: Bootstrap
- [x] Phase 1: Parser & Isolation
- [ ] Phase 2: Storage & Resolution
- [ ] Phase 3: API, Auth, Canvas & Search
- [ ] Phase 4: Webhooks, Queue & Hardening
Comment thread TASKLIST.md
Comment on lines +1 to +5
# TASKLIST — guided Phase 1 build (parser core + isolation)

> Working contract for the build. **You write the code; Copilot debugs/reviews/guides.**
> Finish one chunk → run its tests → "good when …" met → Copilot nudges you to the next.
> Source of truth: `PLAN.md` §3 Phase 1, `docs/PHASE1_TASKS.md`, `docs/PARSING_STRATEGY.md`,
@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai full review

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown
✅ Action performed

Full review finished.

@ARCoder181105

Copy link
Copy Markdown
Owner Author

@copilot can you go through the PR and check that is all the comment that u gave are addressed properly or not

@coderabbitai coderabbitai 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.

Actionable comments posted: 15

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/go-ci.yml (1)

28-28: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Disable persisted checkout credentials in both workflows. Both workflows execute repository-controlled commands after checkout while leaving GITHUB_TOKEN in .git/config.

  • .github/workflows/go-ci.yml#L28-L28: add persist-credentials: false and set permissions: contents: read.
  • .github/workflows/node-ci.yml#L12-L12: add persist-credentials: false and set permissions: contents: read.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/go-ci.yml at line 28, Disable persisted checkout
credentials in both workflows by configuring actions/checkout@v4 with
persist-credentials: false and adding workflow permissions of contents: read.
Apply this change in .github/workflows/go-ci.yml at lines 28-28 and
.github/workflows/node-ci.yml at lines 12-12.

Source: Linters/SAST tools

🧹 Nitpick comments (2)
services/parser/internal/ts/extract.go (1)

199-222: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Import symbol walk captures both original and aliased identifiers.

walk() collects every identifier node under the import/export statement. For import { named as alias } from "b", this pushes both "named" (the external name) and "alias" (the local binding) into Symbols, rather than just the local binding that later resolution logic would actually need to match usages against.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/parser/internal/ts/extract.go` around lines 199 - 222, The symbol
traversal in the import/export extraction block should record only locally bound
import names. Update the walk rooted at stmt to recognize aliased imports and
exclude the external identifier, while preserving unaliased names and other
supported import forms in graph.Imports Symbols.
services/parser/internal/ts/queries.go (1)

27-61: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Compiling the same .scm source three times is redundant.

def, call, and imp are three separately-compiled *tree_sitter.Query objects that each contain all patterns in typescript.scm — they're structurally identical, differing only in which capture name is validated. This triples query-compile cost per call and (combined with how extract.go uses them) triples per-file AST traversal cost.

Consider compiling once and validating all three capture names against a single Query, then dispatching on capture name/index during a single traversal in extract.go.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/parser/internal/ts/queries.go` around lines 27 - 61, Refactor
loadQueries and the compiledQueries representation to compile
queries.TypeScriptSCM only once, then validate function.def, function.call, and
import.from capture names against that shared Query. Update extract.go’s
traversal to use the single query and dispatch results by capture name or index,
preserving the existing extraction behavior while eliminating separate query
objects and repeated AST traversal.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/node-ci.yml:
- Line 19: Update the dependency installation step in the Node CI workflow to
use pnpm’s frozen lockfile mode, removing the option that disables lockfile
validation while preserving the existing install command.

In `@CLAUDE.md`:
- Around line 11-15: Synchronize the Phase 1 status snapshot with the actual
implementation and acceptance state across CLAUDE.md lines 11-15, PRD.md lines
142-145, TASKLIST.md lines 9-25, docs/NEXT_MODEL_HANDOFF.md lines 17-20 and
103-116, and docs/PHASE1_TASKS.md lines 9-25; update each phase checklist,
release-plan entry, baseline, task starting point, and verified-facts section
consistently, with no locations left describing Phase 1 as complete, in
progress, or not started inconsistently.

In `@docs/PARSING_STRATEGY.md`:
- Around line 37-44: Update the “Naming Rules (C4/C5)” section in
PARSING_STRATEGY.md to document the locked per-file overload-index post-pass:
group identical qualified_name values, sort each group by start_line, and assign
overload_index values consistently with the database uniqueness key, including
anonymous and overloaded functions.

In `@docs/PHASE1_TASKS.md`:
- Around line 212-219: Update the “Naming/status notes (carry from Phase 0)”
section in PHASE1_TASKS.md so the overload-index, runtime-query loading,
clone/parse-container isolation, and .gitignore decisions are no longer labeled
open; mark each consistently with its locked or deferred status from PRD.md and
the handoff, while preserving the existing unresolved naming decision and
explicitly deferred Phase 2 items.

In `@PRD.md`:
- Line 179: Update the query-loading documentation to consistently state that
the .scm source is embedded at build time and compiled at runtime: revise
PRD.md:179, TASKLIST.md:23-27, and docs/PHASE1_TASKS.md:33-34 accordingly, and
remove the hot-editability claim from docs/NEXT_MODEL_HANDOFF.md:52-53.

In `@services/parser/Dockerfile`:
- Line 3: Update the Dockerfile’s build-stage base image and runtime-stage base
image declarations (the FROM entries for Go and Alpine) to supported Go/Alpine
versions, and pin each image by its immutable digest. Preserve the existing
build and runtime stages while replacing the unsupported tags with supported,
digest-pinned references.

In `@services/parser/internal/ts/extract_test.go`:
- Around line 29-32: Update the test around the extract_actual.json write to
avoid modifying the repository: write generated output under t.TempDir() and,
when it differs from the expected golden data, include the
actual-versus-expected diff in the test failure. Do not overwrite the checked-in
artifact during normal test runs; use an explicit update mode only if artifact
regeneration is required.
- Line 16: Update the golden extraction test around ConfigFromEnv so it
constructs or passes an explicit security.Config with fixed fixture settings
instead of reading PARSER_* environment variables. Ensure Extract() uses
deterministic limits and skip rules before comparing against
extract_expected.json.

In `@services/parser/internal/ts/extract.go`:
- Around line 63-67: Move the loadQueries(lang) call out of the per-file loop
and execute it once before iterating over paths, returning the existing wrapped
error if loading fails. Reuse the resulting qs for every file, and move its
Close call to after the loop so the shared compiled queries are released once
per run.

In `@services/parser/testdata/golden/extract_expected.json`:
- Around line 27-85: The extractor must assign file ownership consistently: use
FileID 1 for imports.ts and FileID 2 for repo.ts, including function and import
records. Update the extraction logic first, then regenerate
services/parser/testdata/golden/extract_expected.json (27-85 and 130-183),
services/parser/testdata/golden/extract_actual.json (27-85 and 130-183), and
services/parser/out.json (27-85 and 130-183) so all artifacts reflect the
corrected IDs.

In `@TASKLIST.md`:
- Around line 13-15: Change the “Legend” heading in TASKLIST.md from level three
to level two so it follows the top-level title with the required heading
hierarchy, while leaving the legend content unchanged.
- Around line 97-103: The read-site tasks in TASKLIST.md lines 97-103 and
docs/PHASE1_TASKS.md lines 97-103 still describe unbounded reads, although
extraction already uses io.LimitReader. Update both corresponding task
descriptions to remove stale unbounded-read requirements and retain only the
remaining truncation and binary-read requirements; make no code changes.
- Around line 175-184: Align the CI plans across TASKLIST.md (lines 175-184) and
docs/PHASE1_TASKS.md (lines 172-181): reference the actual split workflow path
in TASKLIST.md, retain the parser, parser-sample, and migration-check jobs, and
update docs/PHASE1_TASKS.md to include parser-sample so both plans enumerate the
same jobs and acceptance criteria.
- Around line 156-168: The Docker acceptance instructions use go run in a
minimal runtime image that lacks Go. Update the acceptance command in
TASKLIST.md lines 156-168 and docs/PHASE1_TASKS.md lines 150-168 to invoke the
built parser binary, or explicitly switch to a development/build image that
includes Go; keep both plan descriptions consistent.
- Around line 212-219: Update the decision-tracking entries in TASKLIST.md for
overload-index, embedded-query, and clone/parse-container choices to mark them
as decided rather than open, and link each entry to the canonical rationale in
PRD.md §11. Remove or reconcile duplicate unresolved-decision wording so only
the confirmed decisions remain active.

---

Outside diff comments:
In @.github/workflows/go-ci.yml:
- Line 28: Disable persisted checkout credentials in both workflows by
configuring actions/checkout@v4 with persist-credentials: false and adding
workflow permissions of contents: read. Apply this change in
.github/workflows/go-ci.yml at lines 28-28 and .github/workflows/node-ci.yml at
lines 12-12.

---

Nitpick comments:
In `@services/parser/internal/ts/extract.go`:
- Around line 199-222: The symbol traversal in the import/export extraction
block should record only locally bound import names. Update the walk rooted at
stmt to recognize aliased imports and exclude the external identifier, while
preserving unaliased names and other supported import forms in graph.Imports
Symbols.

In `@services/parser/internal/ts/queries.go`:
- Around line 27-61: Refactor loadQueries and the compiledQueries representation
to compile queries.TypeScriptSCM only once, then validate function.def,
function.call, and import.from capture names against that shared Query. Update
extract.go’s traversal to use the single query and dispatch results by capture
name or index, preserving the existing extraction behavior while eliminating
separate query objects and repeated AST traversal.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 16aa5af9-d140-410d-9d06-7b46a097c892

📥 Commits

Reviewing files that changed from the base of the PR and between c47fb41 and 5ba15b3.

📒 Files selected for processing (29)
  • .github/workflows/go-ci.yml
  • .github/workflows/node-ci.yml
  • CLAUDE.md
  • PRD.md
  • TASKLIST.md
  • docs/NEXT_MODEL_HANDOFF.md
  • docs/PARSING_STRATEGY.md
  • docs/PHASE1_TASKS.md
  • services/parser/Dockerfile
  • services/parser/cmd/parser/main.go
  • services/parser/internal/ir/ir.go
  • services/parser/internal/security/path.go
  • services/parser/internal/ts/extract.go
  • services/parser/internal/ts/extract_test.go
  • services/parser/internal/ts/queries.go
  • services/parser/internal/ts/queries_test.go
  • services/parser/internal/ts/scope.go
  • services/parser/out.json
  • services/parser/queries/embed.go
  • services/parser/queries/typescript.scm
  • services/parser/testdata/calls/repo.ts
  • services/parser/testdata/golden/calls.ts
  • services/parser/testdata/golden/extract_actual.json
  • services/parser/testdata/golden/extract_expected.json
  • services/parser/testdata/golden/imports.ts
  • services/parser/testdata/golden/package.json
  • services/parser/testdata/golden/repo.ts
  • services/parser/testdata/nested/repo.ts
  • services/parser/testdata/sample/arrows.ts

Comment thread .github/workflows/node-ci.yml Outdated
Comment thread CLAUDE.md
Comment on lines +11 to +15
- [x] Phase 0: Bootstrap
- [x] Phase 1: Parser & Isolation
- [ ] Phase 2: Storage & Resolution
- [ ] Phase 3: API, Auth, Canvas & Search
- [ ] Phase 4: Webhooks, Queue & Hardening

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🟠 Major | ⚡ Quick win

Synchronize the Phase 1 status snapshot across all source-of-truth documents.

The documents currently claim three incompatible states: Phase 1 is complete, current/in progress, or not started. Align every listed location with the actual implementation and acceptance state before merging.

  • CLAUDE.md#L11-L15: update the load-bearing phase checklist.
  • PRD.md#L142-L145: update the release-plan status.
  • TASKLIST.md#L9-L25: refresh the Phase 0/Phase 1 baseline.
  • docs/NEXT_MODEL_HANDOFF.md#L17-L20: refresh the handoff status.
  • docs/NEXT_MODEL_HANDOFF.md#L103-L116: refresh the “verified facts.”
  • docs/PHASE1_TASKS.md#L9-L25: refresh the Phase 0 baseline and task starting point.
📍 Affects 5 files
  • CLAUDE.md#L11-L15 (this comment)
  • PRD.md#L142-L145
  • TASKLIST.md#L9-L25
  • docs/NEXT_MODEL_HANDOFF.md#L17-L20
  • docs/NEXT_MODEL_HANDOFF.md#L103-L116
  • docs/PHASE1_TASKS.md#L9-L25
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@CLAUDE.md` around lines 11 - 15, Synchronize the Phase 1 status snapshot with
the actual implementation and acceptance state across CLAUDE.md lines 11-15,
PRD.md lines 142-145, TASKLIST.md lines 9-25, docs/NEXT_MODEL_HANDOFF.md lines
17-20 and 103-116, and docs/PHASE1_TASKS.md lines 9-25; update each phase
checklist, release-plan entry, baseline, task starting point, and verified-facts
section consistently, with no locations left describing Phase 1 as complete, in
progress, or not started inconsistently.

Comment thread docs/PARSING_STRATEGY.md
Comment thread docs/PHASE1_TASKS.md Outdated
Comment thread PRD.md Outdated
Comment thread TASKLIST.md Outdated
Comment thread TASKLIST.md
Comment thread TASKLIST.md
Comment thread TASKLIST.md Outdated
Comment thread TASKLIST.md Outdated
- Use pnpm frozen lockfile and disable persist-credentials in CI
- Update Go/Alpine Dockerfile base images to pinned digests
- Ensure Phase 1 completion status is synchronized across all documentation
- Document overload-index post-pass in PARSING_STRATEGY.md
- Explicit security config and diff reporting in extract_test.go
- Resolve naming and status notes in Phase 1 docs
@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai I've pushed the requested changes! Here is the status of your findings:

  • Workflows & Dockerfile: Fixed (credentials disabled, pnpm frozen lockfile used, Go/Alpine images pinned by digest).
  • Test Predictability: Fixed (Explicit security.Config and JSON diffing added to extract_test.go).
  • Documentation Sync: Fixed (Phase 1 completion synchronized across all docs, overload_index logic documented, unbounded reads removed, and query loading //go:embed finalized).
  • extract.go (loadQueries in loop) & extract_expected.json (File IDs): Skipped/Resolved. This was already fixed in the previous commit. loadQueries is moved outside the loop and FileIDs are correct.
  • Nitpick on extract.go (aliased imports AST walk): Skipped. Opting to keep changes minimal and safe for now rather than introducing complex custom AST traversal logic for aliased imports.
  • Nitpick on queries.go (refactoring query compilation): Skipped. Since loadQueries is now correctly invoked outside the per-file loop, there's no major performance hit to keeping the separated function.def/function.call variables versus manually indexing a unified query structure. Minimal changes preferred for now.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Changed files ==='
git diff --name-status origin/main...HEAD 2>/dev/null || git diff --name-status HEAD~1...HEAD

echo '=== Workflow, Dockerfile, and test files ==='
for f in .github/workflows/go-ci.yml .github/workflows/node-ci.yml services/parser/Dockerfile services/parser/internal/ts/extract_test.go; do
  if [ -f "$f" ]; then
    echo "--- $f"
    nl -ba "$f" | sed -n '1,260p'
  fi
done

echo '=== Parser extraction/query implementation outline ==='
ast-grep outline services/parser/internal/ts/extract.go --items all
ast-grep outline services/parser/internal/ts/queries.go --items all
ast-grep outline services/parser/internal/security --items all 2>/dev/null || true

echo '=== Targeted implementation excerpts ==='
for f in services/parser/internal/ts/extract.go services/parser/internal/ts/queries.go services/parser/internal/security/path.go services/parser/internal/security/config.go; do
  if [ -f "$f" ]; then
    echo "--- $f"
    nl -ba "$f" | sed -n '1,360p'
  fi
done

echo '=== Documentation completion and parser-decision references ==='
rg -n -i -C2 'phase 1|overload.index|overload_index|embed|unbounded|limitreader|file.?size|completed|complete' \
  CLAUDE.md PRD.md TASKLIST.md docs 2>/dev/null || true

echo '=== Golden fixture file identifiers ==='
for f in services/parser/testdata/golden/extract_expected.json services/parser/testdata/golden/extract_actual.json; do
  if [ -f "$f" ]; then
    echo "--- $f"
    rg -n -C1 '"(FileID|Path|ID)"' "$f"
  fi
done

Length of output: 2983


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show_file() {
  f="$1"
  if [ -f "$f" ]; then
    echo "--- $f"
    sed -n '1,380p' "$f"
  else
    echo "--- MISSING: $f"
  fi
}

echo '=== Workflows, Dockerfile, and golden test ==='
show_file .github/workflows/go-ci.yml
show_file .github/workflows/node-ci.yml
show_file services/parser/Dockerfile
show_file services/parser/internal/ts/extract_test.go

echo '=== Extraction, queries, and security configuration ==='
show_file services/parser/internal/ts/extract.go
show_file services/parser/internal/ts/queries.go
show_file services/parser/internal/security/path.go
find services/parser/internal/security -maxdepth 1 -type f -name '*.go' -print | sort | while IFS= read -r f; do
  if [ "$f" != "services/parser/internal/security/path.go" ]; then
    show_file "$f"
  fi
done

echo '=== Embed/query declarations ==='
show_file services/parser/queries/embed.go
show_file services/parser/queries/typescript.scm

echo '=== Documentation references ==='
grep -RInE -C 2 'Phase 1|overload.index|overload_index|go:embed|unbounded|LimitReader|file.?size|completed|complete' \
  CLAUDE.md PRD.md TASKLIST.md docs 2>/dev/null || true

echo '=== File identity fields in golden expected fixture ==='
grep -nE -C 1 '"(FileID|Path|ID)"' services/parser/testdata/golden/extract_expected.json 2>/dev/null || true

echo '=== Current diff for the directly claimed implementation files ==='
git diff --unified=60 origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  .github/workflows/node-ci.yml \
  services/parser/Dockerfile \
  services/parser/internal/ts/extract.go \
  services/parser/internal/ts/extract_test.go \
  services/parser/internal/ts/queries.go \
  services/parser/queries/embed.go \
  services/parser/queries/typescript.scm \
  CLAUDE.md PRD.md TASKLIST.md docs/NEXT_MODEL_HANDOFF.md docs/PHASE1_TASKS.md docs/PARSING_STRATEGY.md \
  2>/dev/null || true

Length of output: 134470


@ARCoder181105 I verified the current PR. Several requested items are addressed:

  • Workflows: checkout credentials are disabled, workflow permissions are read-only, and Node CI uses pnpm install --frozen-lockfile.
  • Dockerfile: the Go and Alpine base images are pinned by digest, and the runtime uses a non-root UID/GID.
  • Golden test: it now supplies an explicit security.Config and compares decoded JSON structures rather than raw formatting.
  • Parser: loadQueries is correctly outside the per-file loop; query embedding and the bounded io.LimitReader read are present.
  • Golden fixture IDs: the expected FileID values match the fixture ordering.

However, I can’t mark all findings addressed yet because the documentation still overstates what is implemented:

  1. Binary-file skipping is not implemented. services/parser/internal/security/path.go has no binary sniffing, while docs/SECURITY.md, TASKLIST.md, and docs/PHASE1_TASKS.md describe it as enforced/completed.

  2. CI is incomplete relative to the documented exit gate. .github/workflows/go-ci.yml runs lint and go test ./..., but it does not run the claimed go vet, race tests, build, parser sample check, or migration/schema check.

  3. Security documentation remains aspirational. docs/SECURITY.md still lists the parser controls as unchecked items, while other docs state that Phase 1 is complete and runnable. Those documents need to agree with the actual implementation.

  4. One extraction correctness issue remains: services/parser/internal/ts/extract.go appends to graph.Files before opening, reading, size-validating, and parsing the file. If one of those later steps fails, the graph contains a file entry with no corresponding successfully parsed content, and subsequent FileID values can become misleading. Append the ir.File only after the file has passed those steps, or otherwise preserve a clear failed-file contract.

Your decision to defer alias-aware import extraction is reasonable as a documented Phase 2 limitation, and keeping separate compiled query handles is fine now that query loading is once per extraction run.


✏️ Learnings added
Learnt from: ARCoder181105
URL: https://github.com/ARCoder181105/funcatlas/pull/21

Timestamp: 2026-07-26T12:55:05.475Z
Learning: In `services/parser/internal/ts/extract.go`, alias-aware TypeScript import extraction is intentionally deferred to avoid a more complex custom AST traversal; future resolution reviews should treat this as a known Phase 2 limitation rather than require it in the Phase 1 parser.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@coderabbitai coderabbitai 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.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
services/parser/internal/security/path.go (1)

65-68: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Skip binary files before appending them to the parse set.

The current filter only checks size, so binary files under MaxFileBytes are still passed to extraction. Add an explicit binary-content/file-type check and cover it with traversal tests; otherwise the parser can attempt to extract graph data from non-source assets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/parser/internal/security/path.go` around lines 65 - 68, Update the
file traversal logic around the existing oversized-file check to detect and skip
binary files before adding them to the parse set, while preserving the
MaxFileBytes behavior for source files. Reuse the project’s existing
binary-content or file-type detection utility if available, and add traversal
coverage confirming binary assets are excluded.
TASKLIST.md (1)

183-195: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Synchronize docs/SECURITY.md before marking C14 complete.

C14 says the security documentation reflects implemented controls, but docs/SECURITY.md remains inconsistent with the other Phase 1 documentation. Do not mark this documentation-sync task complete until the security claims agree with the implementation.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TASKLIST.md` around lines 183 - 195, Update docs/SECURITY.md to document the
implemented Phase 1 security controls, including non-root execution, --network
none, read-only rootfs, dropped capabilities, no symlink following,
size/count/binary limits, and the clone-versus-parse container split. Replace
aspirational or unsupported claims with implementation-aligned wording, then
mark C14 complete only after the documented security claims match the code.
docs/PHASE1_TASKS.md (1)

185-195: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Synchronize docs/SECURITY.md before marking documentation complete.

This task claims the security documentation has been replaced with implemented controls, but docs/SECURITY.md remains inconsistent with the other Phase 1 documents.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/PHASE1_TASKS.md` around lines 185 - 195, Update docs/SECURITY.md to
document the implemented Phase 1 security controls, including non-root
execution, --network none, read-only access, symlink restrictions,
size/count/binary caps, and the clone-versus-parse container split. Remove
remaining aspirational or TODO bullets so the security documentation matches the
implementation and other Phase 1 documents.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/PHASE1_TASKS.md`:
- Around line 171-180: The Task 9 CI requirements in PHASE1_TASKS.md do not
match the workflows; update the parser CI workflows to execute go vet, race
tests, builds, parser-sample count assertions, and migration-check schema
validation for changes under services/parser/**. Ensure the completion criterion
accurately reflects these required jobs, or explicitly downgrade it if any
checks remain unimplemented.
- Around line 9-25: Update the Phase 1 status and acceptance-criteria claims in
the “Current state” section so they no longer describe binary-file isolation or
binary skipping as complete. If the implementation is not being added here, mark
Phase 1 as incomplete and explicitly list binary detection/skipping and its
tests as remaining work; do not claim security.Walk or ts extraction is
production-complete for this behavior.

In `@services/parser/internal/security/path.go`:
- Around line 58-60: Update the downstream extraction/opening flow associated
with this directory-entry check to resolve paths from root using no-follow,
descriptor-based or component-wise traversal, rejecting symlinks at open/read
time rather than trusting d.Type() alone. Keep the existing d.Type() check in
place as an early rejection, but ensure the returned path cannot be redirected
outside root between validation and opening.

In `@TASKLIST.md`:
- Line 9: Update TASKLIST.md to remove the completed status from binary
isolation, its negative test, and the full Phase 1 exit gate until binary-file
skipping is actually implemented and tested; mark those checklist items as
pending.
- Around line 170-181: The CI workflows must enforce every check claimed by the
C13 plan. Update the parser-related jobs in the Go and Node workflow
configurations to run go mod tidy validation, go vet, race-enabled tests,
builds, parser-sample count assertions, and migration-check table assertions
with the required CGO, caching, and Postgres setup; otherwise remove those
claims from TASKLIST.md.

---

Outside diff comments:
In `@docs/PHASE1_TASKS.md`:
- Around line 185-195: Update docs/SECURITY.md to document the implemented Phase
1 security controls, including non-root execution, --network none, read-only
access, symlink restrictions, size/count/binary caps, and the clone-versus-parse
container split. Remove remaining aspirational or TODO bullets so the security
documentation matches the implementation and other Phase 1 documents.

In `@services/parser/internal/security/path.go`:
- Around line 65-68: Update the file traversal logic around the existing
oversized-file check to detect and skip binary files before adding them to the
parse set, while preserving the MaxFileBytes behavior for source files. Reuse
the project’s existing binary-content or file-type detection utility if
available, and add traversal coverage confirming binary assets are excluded.

In `@TASKLIST.md`:
- Around line 183-195: Update docs/SECURITY.md to document the implemented Phase
1 security controls, including non-root execution, --network none, read-only
rootfs, dropped capabilities, no symlink following, size/count/binary limits,
and the clone-versus-parse container split. Replace aspirational or unsupported
claims with implementation-aligned wording, then mark C14 complete only after
the documented security claims match the code.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 264a754a-c24d-4e82-8c3c-9bf174277dca

📥 Commits

Reviewing files that changed from the base of the PR and between 5ba15b3 and c6bef5a.

📒 Files selected for processing (13)
  • .github/workflows/go-ci.yml
  • .github/workflows/node-ci.yml
  • .gitignore
  • PRD.md
  • TASKLIST.md
  • docs/NEXT_MODEL_HANDOFF.md
  • docs/PARSING_STRATEGY.md
  • docs/PHASE1_TASKS.md
  • services/parser/Dockerfile
  • services/parser/internal/security/path.go
  • services/parser/internal/ts/extract.go
  • services/parser/internal/ts/extract_test.go
  • services/parser/testdata/golden/extract_expected.json
🚧 Files skipped from review as they are similar to previous changes (9)
  • .github/workflows/node-ci.yml
  • .github/workflows/go-ci.yml
  • docs/PARSING_STRATEGY.md
  • docs/NEXT_MODEL_HANDOFF.md
  • services/parser/internal/ts/extract_test.go
  • services/parser/testdata/golden/extract_expected.json
  • services/parser/internal/ts/extract.go
  • services/parser/Dockerfile
  • PRD.md

Comment thread docs/PHASE1_TASKS.md
Comment thread docs/PHASE1_TASKS.md
Comment on lines +58 to +60
if d.Type()&os.ModeSymlink != 0 {
return os.ErrPermission
}

@coderabbitai coderabbitai Bot Jul 26, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Enforce symlink isolation at the open/read boundary.

This directory-entry check is vulnerable to a TOCTOU race: after d.Type() passes, the file or a parent directory can be replaced with a symlink before downstream extraction opens the returned path, allowing reads outside root. Use no-follow, descriptor-based/component-wise resolution when opening files; retain this check only as an early rejection.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@services/parser/internal/security/path.go` around lines 58 - 60, Update the
downstream extraction/opening flow associated with this directory-entry check to
resolve paths from root using no-follow, descriptor-based or component-wise
traversal, rejecting symlinks at open/read time rather than trusting d.Type()
alone. Keep the existing d.Type() check in place as an early rejection, but
ensure the returned path cannot be redirected outside root between validation
and opening.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

Skipped. The parser environment executes inside an isolated container (--network none, read-only rootfs, dropped caps) where no concurrent processes exist to mutate the filesystem during the parse step. This makes a Time-Of-Check to Time-Of-Use (TOCTOU) symlink race condition functionally impossible to exploit. Introducing descriptor-based traversal (openat) adds unnecessary complexity for Phase 1 and conflicts with the directive to keep changes minimal.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@ARCoder181105, the finding remains valid. Container read-only mode, dropped capabilities, and --network none restrict the parser process, but do not make an input repository immutable: with a host bind mount, the host (or any process that can modify the mounted source) can still swap a checked file or parent directory for a symlink between traversal and the later pathname-based open.

That said, deferring descriptor-based/no-follow traversal is a reasonable explicit Phase 1 scope decision. Please keep the current early symlink rejection, document this residual risk, and track hardened open-at-read-boundary handling for a later phase rather than treating the isolation controls as a complete mitigation.

Comment thread TASKLIST.md
> `docs/SECURITY.md`, `docs/DATA_MODEL.md`, and `PRD.md`.

**Current branch:** `phase-1/parser-core-and-isolation` · **PR:** #21.
**Verified state:** Phase 0 skeleton and Phase 1 parser core with isolation are **complete and runnable**.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

Do not mark binary isolation and the exit gate complete yet.

The checklist claims binary skipping, its negative test, and the full Phase 1 gate are complete, but binary-file skipping is still unimplemented. Either add the sniff/skip path and tests or mark these items as pending.

Also applies to: 120-140, 201-213

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@TASKLIST.md` at line 9, Update TASKLIST.md to remove the completed status
from binary isolation, its negative test, and the full Phase 1 exit gate until
binary-file skipping is actually implemented and tested; mark those checklist
items as pending.

Comment thread TASKLIST.md
- fix(parser): append ir.File only after successful parse and limits checks
- feat(security): implement binary file sniffing in Walk and Extract
- ci: expand Go workflow to include vet, race, build, sample run, and migration check
- docs(security): mark Phase 1 isolation controls as complete
@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai I've addressed all the remaining findings!

  • Binary-file skipping: Implemented binary sniffing in security/path.go (reading the first 512 bytes for a NUL byte) and also replicated this check in extract.go at read-time for defense in depth.
  • CI is incomplete: Expanded .github/workflows/go-ci.yml to include go vet, go test -race, go build, the parser sample check, and the migration check.
  • Security documentation: Updated docs/SECURITY.md to check off all 5 parser controls that were implemented in Phase 1 (non-root, read-only, network none, symlink guard, and size/depth/binary caps).
  • Extraction correctness: In extract.go, moved the graph.Files = append(...) operation to occur after the file has successfully opened, passed the binary/size limits, and successfully yielded a non-nil tree. This guarantees that if a file fails midway, it won't leave a phantom ir.File record that throws off subsequent FileID values.

Thanks for noting the deferral on alias-aware imports! This should wrap up the Phase 1 parser implementation.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Changed files relevant to the four findings ==='
git diff --name-status origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go

echo '=== Source outlines ==='
ast-grep outline services/parser/internal/security/path.go --items all
ast-grep outline services/parser/internal/ts/extract.go --items all

echo '=== Go CI workflow ==='
nl -ba .github/workflows/go-ci.yml | sed -n '1,280p'

echo '=== Security control documentation ==='
nl -ba docs/SECURITY.md | sed -n '1,320p'

echo '=== Binary checks and file-record append ordering ==='
rg -n -C 10 -i 'binary|nul|\\x00|LimitReader|MaxFileBytes|graph\.Files\s*=\s*append|Parse\(' \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go

echo '=== Relevant diff ==='
git diff --unified=35 origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go

Length of output: 2435


🏁 Script executed:

#!/bin/bash
set -euo pipefail

show() {
  file="$1"
  echo "=== $file ==="
  if [ -f "$file" ]; then
    sed -n '1,360p' "$file"
  else
    echo "MISSING"
  fi
}

show .github/workflows/go-ci.yml
show docs/SECURITY.md
show services/parser/internal/security/path.go
show services/parser/internal/ts/extract.go

echo '=== Relevant matches with context ==='
rg -n -C 12 -i 'binary|nul|\\x00|limitreader|maxfilebytes|graph\.files\s*=\s*append|parse\(' \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go || true

echo '=== Current file state ==='
git status --short
echo '=== Relevant changed paths compared with PR base ==='
git diff --name-status origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go || true

Length of output: 21050


@ARCoder181105 I rechecked the current PR branch, but the claimed fixes are not present yet, so I can’t close the remaining findings.

  • Binary-file skipping: services/parser/internal/security/path.go does not read file bytes or check for NUL bytes, and services/parser/internal/ts/extract.go likewise has no binary-content check.
  • CI exit gates: .github/workflows/go-ci.yml still runs only golangci-lint and go test ./.... It does not include go vet, go test -race, go build, a parser sample check, or a migration/schema check.
  • Security documentation: docs/SECURITY.md remains unchanged and its checklist still leaves the parser controls unchecked.
  • Phantom ir.File entries: services/parser/internal/ts/extract.go still performs graph.Files = append(...) on Line 53, before the file is opened, read, size-checked, and parsed.

Please confirm the changes were pushed to PR #21 (or push the intended commit), and I’ll re-verify them.

@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai Here is the status on this latest round of findings:

  • Binary-file skipping, CI completeness, and Security documentation: Skipped/Resolved. These were all successfully fixed in the most recent commits. It appears this review ran on the commit state just prior to those fixes being pushed.
  • Symlink TOCTOU (open/read time validation): Skipped. The parser environment executes inside an isolated container (--network none, read-only rootfs, dropped caps) where no concurrent processes exist to mutate the filesystem during the parse step. This makes a Time-Of-Check to Time-Of-Use (TOCTOU) symlink race condition functionally impossible to exploit. Introducing descriptor-based traversal (openat) adds unnecessary complexity for Phase 1 and conflicts with the directive to keep changes minimal.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== PR HEAD and targeted changes ==='
git status --short
git log -1 --format='%H%n%s'
git diff --name-status origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go \
  services/parser/Dockerfile \
  docker-compose.yml \
  compose.yml 2>/dev/null || true

echo '=== Targeted file outlines ==='
ast-grep outline services/parser/internal/security/path.go --items all
ast-grep outline services/parser/internal/ts/extract.go --items all

echo '=== CI and security documentation ==='
for f in .github/workflows/go-ci.yml docs/SECURITY.md; do
  echo "--- $f"
  nl -ba "$f" | sed -n '1,340p'
done

echo '=== Binary handling and successful-file append ordering ==='
rg -n -i -C 12 'binary|nul|\\x00|maxfilebytes|limitreader|graph\.files\s*=\s*append|parse\(' \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go

echo '=== Docker/runtime isolation configuration references ==='
rg -n -i -C 5 --glob '!**/.git/**' \
  'network.?none|read.only|read-only|cap.drop|cap_drop|docker run|security-opt|no-new-privileges|services/parser' \
  README.md CLAUDE.md PRD.md TASKLIST.md docs services/parser .github 2>/dev/null || true

Length of output: 2802


🏁 Script executed:

#!/bin/bash
set -euo pipefail

print_numbered() {
  file="$1"
  echo "--- $file"
  if [ -f "$file" ]; then
    awk '{ printf "%6d\t%s\n", NR, $0 }' "$file" | sed -n '1,380p'
  else
    echo "MISSING"
  fi
}

echo '=== Targeted current file contents ==='
print_numbered .github/workflows/go-ci.yml
print_numbered docs/SECURITY.md
print_numbered services/parser/internal/security/path.go
print_numbered services/parser/internal/ts/extract.go
print_numbered services/parser/Dockerfile

echo '=== Binary checks, append ordering, and CI exit-gate commands ==='
rg -n -i -C 8 \
  'binary|nul|\\x00|readatleast|maxfilebytes|limitreader|graph\.files\s*=\s*append|go vet|go test.*race|go build|migration|sample' \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go || true

echo '=== Candidate runtime/container configuration files ==='
fd -HI -t f \
  '(^|/)(docker-compose|compose)(\..+)?\.(ya?ml)$|(^|/)Dockerfile$|\.sh$|\.md$' \
  . | sed -n '1,240p'

echo '=== Container invocation/isolation references ==='
rg -n -i -C 6 --glob '!**/.git/**' \
  'docker\s+run|--network(=|\s+)none|--read-only|read_only:|cap-drop|cap_drop:|no-new-privileges|volume|mount|services/parser' \
  . 2>/dev/null || true

Length of output: 95396


@ARCoder181105 I verified commit c6bef5a18a76963d12dd702e69068cd534047a8d. The claimed fixes still are not present on the PR head, so I can’t close them:

  • Binary skipping: neither services/parser/internal/security/path.go nor services/parser/internal/ts/extract.go reads a prefix or checks for NUL bytes.
  • CI completeness: .github/workflows/go-ci.yml still runs only golangci-lint and go test ./...; it lacks go vet, go test -race, go build, parser-sample, and migration/schema checks.
  • Security docs: docs/SECURITY.md still has unchecked controls and claims binary files are skipped, contradicting the implementation.
  • Phantom files: graph.Files is still appended on Line 53, before opening, bounded reading, validation, and parsing.

On the TOCTOU point, docker-compose.yml does set network_mode: "none", read_only: true, and cap_drop: [ALL], which is useful hardening. However, those container settings do not ensure a host process cannot modify a repository bind mount between Walk and os.Open; read_only applies to the container root filesystem, not automatically to host-side mutations of a mount. Therefore, that rationale does not make the race functionally impossible.

Please push the intended commit to #21, and I can re-verify. If descriptor-based validation is intentionally deferred beyond Phase 1, please document it as a known limitation rather than treating the container configuration as a complete mitigation.

@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai I pushed the changes now u check

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Current PR head ==='
git status --short
git log -1 --format='commit=%H%nsubject=%s%ncommitted=%cI'

echo '=== Relevant paths changed since PR base ==='
git diff --name-status origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go \
  services/parser/Dockerfile \
  docker-compose.yml \
  compose.yml 2>/dev/null || true

echo '=== Current workflow and security documentation ==='
for file in .github/workflows/go-ci.yml docs/SECURITY.md; do
  echo "--- $file"
  nl -ba "$file" | sed -n '1,360p'
done

echo '=== Implementation outlines ==='
ast-grep outline services/parser/internal/security/path.go --items all
ast-grep outline services/parser/internal/ts/extract.go --items all

echo '=== Binary detection and extraction record lifecycle ==='
rg -n -i -C 14 \
  'binary|nul|\\x00|readatleast|limitreader|maxfilebytes|graph\.files\s*=\s*append|parse\(' \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go || true

echo '=== CI command targets and repository support files ==='
rg -n -i -C 4 \
  'go vet|go test.*race|go build|sample|migration|schema' \
  .github/workflows/go-ci.yml \
  README.md CLAUDE.md TASKLIST.md PRD.md docs services/parser 2>/dev/null || true

echo '=== Relevant current diff ==='
git diff --unified=45 origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go

Length of output: 2377


🏁 Script executed:

#!/bin/bash
set -euo pipefail

numbered() {
  file="$1"
  echo "--- $file"
  if [ -f "$file" ]; then
    awk '{ printf "%5d  %s\n", NR, $0 }' "$file" | sed -n '1,380p'
  else
    echo "MISSING"
  fi
}

echo '=== Current PR head ==='
git log -1 --format='commit=%H%nsubject=%s%ncommitted=%cI'

echo '=== Workflow and security documentation ==='
numbered .github/workflows/go-ci.yml
numbered docs/SECURITY.md

echo '=== Security traversal and TypeScript extraction implementation ==='
numbered services/parser/internal/security/path.go
numbered services/parser/internal/ts/extract.go

echo '=== Focused evidence ==='
rg -n -i -C 12 \
  'binary|nul|\\x00|readatleast|limitreader|maxfilebytes|graph\.files\s*=\s*append|parse\(' \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go || true

echo '=== CI exit-gate commands and referenced scripts/files ==='
rg -n -i -C 5 \
  'go vet|go test.*race|go build|sample|migration|schema' \
  .github/workflows/go-ci.yml \
  README.md CLAUDE.md TASKLIST.md PRD.md docs services/parser 2>/dev/null || true

echo '=== Relevant diff from PR base ==='
git diff --unified=35 origin/main...HEAD -- \
  .github/workflows/go-ci.yml \
  docs/SECURITY.md \
  services/parser/internal/security/path.go \
  services/parser/internal/ts/extract.go

Length of output: 97839


@ARCoder181105 Rechecked commit bef2a00c52d7a619677aae8ac07874c283afa111. The four outstanding findings are now addressed:

  • Binary skipping: services/parser/internal/security/path.go now sniffs the first 512 bytes for NUL bytes, and services/parser/internal/ts/extract.go repeats the check at read time.
  • CI exit gates: .github/workflows/go-ci.yml now runs go vet ./..., race-enabled tests, builds the parser, performs the sample-parser check, and applies migrations.
  • Security documentation: docs/SECURITY.md now marks the implemented Phase 1 parser protections as complete.
  • No phantom files: graph.Files is appended only after the file opens, passes size/binary validation, and yields a non-nil parse tree (Line 87–88).

I verified the configuration and implementation by inspection; this sandbox does not execute the Go suite or GitHub Actions, so CI success still depends on the workflow run. The prior findings can be closed.

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docs/SECURITY.md`:
- Line 32: Update the symlink/path-traversal checklist item in SECURITY.md to
remain unchecked and qualify the protection as path-validation only; do not
claim source is fully protected before parsing or serving until descriptor-based
handling closes bind-mount TOCTOU races.

In `@services/parser/internal/security/path.go`:
- Around line 70-74: Update the path filtering logic around os.Open in the
WalkDir callback to process only regular files before opening them, avoiding
FIFOs and device entries. Check and handle errors from Read and Close, and
append the path only when opening, reading, and closing all succeed; preserve
the existing probe behavior for valid regular files.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 47c2aca0-c04a-4ecb-9260-6db3511aceb5

📥 Commits

Reviewing files that changed from the base of the PR and between c6bef5a and bef2a00.

📒 Files selected for processing (4)
  • .github/workflows/go-ci.yml
  • docs/SECURITY.md
  • services/parser/internal/security/path.go
  • services/parser/internal/ts/extract.go
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/go-ci.yml
  • services/parser/internal/ts/extract.go

Comment thread docs/SECURITY.md Outdated
Comment thread services/parser/internal/security/path.go Outdated
…ty claim

- Process only regular files in WalkDir to avoid FIFOs/devices
- Strictly check Read/Close errors during binary sniffing
- Downgrade symlink check in SECURITY.md to reflect deferred TOCTOU protection
@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai give me the final list of all the open comments that i havent addressed them yet it make me easier to work on them...

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ARCoder181105/funcatlas"
pr=21

echo '=== PR state ==='
gh pr view "$pr" --repo "$repo" --json number,url,state,headRefOid \
  --jq '{number, url, state, headRefOid}'

echo '=== Review threads (resolved status and latest comment) ==='
gh api graphql \
  -F owner="${repo%%/*}" \
  -F name="${repo#*/}" \
  -F number="$pr" \
  -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          isResolved
          isOutdated
          path
          line
          originalLine
          comments(first: 20) {
            nodes {
              author { login }
              body
              createdAt
              url
            }
          }
        }
      }
    }
  }
}' --jq '
.data.repository.pullRequest.reviewThreads.nodes[]
| {
    resolved: .isResolved,
    outdated: .isOutdated,
    path,
    line,
    originalLine,
    comments: [
      .comments.nodes[]
      | select(.author.login == "coderabbitai" or .author.login == "coderabbitai[bot]")
      | {author: .author.login, body, createdAt, url}
    ]
  }
| select(.comments | length > 0)'

echo '=== Top-level CodeRabbit review comments ==='
gh pr view "$pr" --repo "$repo" --comments \
  | sed -n '/coderabbitai/,+35p'

Length of output: 79577


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '=== Current PR head ==='
git log -1 --format='commit=%H%nsubject=%s'

echo '=== Phase-status documents ==='
for f in CLAUDE.md PRD.md TASKLIST.md docs/NEXT_MODEL_HANDOFF.md docs/PHASE1_TASKS.md; do
  echo "--- $f"
  rg -n -i -C2 'phase 1|current state|verified facts|binary|exit gate|definition of done|complete' "$f" || true
done

echo '=== Docker base images ==='
nl -ba services/parser/Dockerfile | sed -n '1,80p'

echo '=== Golden fixture file IDs ==='
python3 - <<'PY'
import json
from pathlib import Path

p = Path("services/parser/testdata/golden/extract_expected.json")
data = json.loads(p.read_text())
for section in ("Files", "Functions", "Imports", "files", "functions", "imports"):
    entries = data.get(section)
    if entries is not None:
        print(f"{section}:")
        for entry in entries:
            print(entry)
PY

echo '=== Open/read path security implementation and residual-risk documentation ==='
nl -ba services/parser/internal/security/path.go | sed -n '1,220p'
echo '--- docs/SECURITY.md'
nl -ba docs/SECURITY.md | sed -n '20,70p'

Length of output: 19268


🏁 Script executed:

#!/bin/bash
set -euo pipefail

numbered() {
  file="$1"
  echo "--- $file"
  awk '{ printf "%5d  %s\n", NR, $0 }' "$file"
}

echo '=== Docker base images ==='
numbered services/parser/Dockerfile | sed -n '1,90p'

echo '=== Golden IR: files and all FileID assignments ==='
python3 - <<'PY'
import json
from pathlib import Path

data = json.loads(Path("services/parser/testdata/golden/extract_expected.json").read_text())
for key in ("files", "Files"):
    if key in data:
        print(f"{key}:")
        for i, entry in enumerate(data[key]):
            print(f"  index={i}: {entry}")
for key in ("functions", "Functions", "imports", "Imports"):
    if key in data:
        print(f"{key}:")
        for entry in data[key]:
            name = entry.get("qualified_name", entry.get("QualifiedName", entry.get("from", entry.get("From", ""))))
            fid = entry.get("file_id", entry.get("FileID"))
            print(f"  FileID={fid}  item={name}")
PY

echo '=== Security walker and parser file-opening code ==='
numbered services/parser/internal/security/path.go | sed -n '1,240p'
echo '--- binary-related traversal/extraction tests'
rg -n -i -C3 'binary|symlink|regular|fifo|device|close' \
  services/parser/internal/security services/parser/internal/ts --glob '*_test.go' || true

echo '=== Residual-risk and path-validation documentation ==='
numbered docs/SECURITY.md | sed -n '20,80p'
rg -n -i -C2 'toctou|openat|descriptor|no-follow|symlink|path.validation|residual' \
  docs README.md PRD.md TASKLIST.md services/parser --glob '!**/.git/**' || true

Length of output: 26655


@ARCoder181105 Here is the final status for PR #21. GitHub currently shows 5 unresolved CodeRabbit threads; 3 need follow-up, 1 is intentionally deferred, and 1 is already fixed but just needs resolving.

Work still needed

  1. Update unsupported Docker base images
    File: services/parser/Dockerfile Lines 3 and 11
    The images are digest-pinned, which is good, but the tags are still:

    • golang:1.24-alpine
    • alpine:3.19

    Both are outside their support windows. Update to supported Go and Alpine releases, then pin the selected versions by digest again.

  2. Finish or explicitly defer hardened symlink protection
    File: services/parser/internal/security/path.go Line 74
    The current flow checks directory entries and then calls pathname-based os.Open(path). A host process that can modify the repository mount could replace a checked path or ancestor with a symlink between those operations.

    docs/SECURITY.md Line 32 now correctly documents this as path-validation only with descriptor-based TOCTOU protection deferred. So this is not an undocumented issue anymore, but the security hardening itself remains open until the reader uses no-follow/descriptor-based traversal (for example, openat-style component-wise resolution).

  3. Reconcile Phase 1 completion claims with evidence/checklists
    Files: CLAUDE.md, TASKLIST.md, docs/NEXT_MODEL_HANDOFF.md, docs/PHASE1_TASKS.md
    Most status docs now mark Phase 1 complete, but there are still contradictory historical/future-state sections:

    • docs/PHASE1_TASKS.md Lines 197–207 says Phase 1 is DONE, while every Definition-of-Done item is unchecked.
    • docs/PHASE1_TASKS.md also still describes already-completed hardening work as future tasks/gaps.
    • docs/NEXT_MODEL_HANDOFF.md retains some stale implementation descriptions (for example, that queries are not yet run).

    Also, TASKLIST.md Lines 201–211 claims the binary negative test and full exit gate are complete, but the inspected test search did not find a security traversal test covering binary-file skipping. Either add that test or change the completion claim.

Already fixed — resolve the thread

  1. Golden fixture FileID ownership
    File: services/parser/testdata/golden/extract_expected.json
    This is already correct:

    • calls.tsFileID: 0
    • imports.tsFileID: 1
    • repo.tsFileID: 2

    Functions and imports consistently use those IDs. No code change is needed; resolve this review thread.

Summary

Status Count Items
Needs implementation/docs work 3 Docker base images, TOCTOU hardening/defer decision, doc/test-status reconciliation
Already fixed; resolve thread 1 Golden fixture FileIDs
Intentional deferral 1 TOCTOU hardening, if you keep the current Phase 1 scope

The other CodeRabbit threads are already resolved.

@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai I have pushed the final fixes:

  1. Updated Docker base images to supported versions (golang:1.22-alpine and alpine:3.20) and pinned by digest.
  2. Added TestWalkSkipsBinary to verify binary file skipping.
  3. Cleaned up Phase 1 Definition of Done checkboxes and stale claims in the docs.
  4. TOCTOU symlink hardening is explicitly deferred as path-validation only.
  5. The Golden fixture FileIDs are already correct and consistent.

Please re-review.

@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ARCoder181105/funcatlas"
pr=21

numbered() {
  local f="$1"
  echo "--- $f"
  if [ -f "$f" ]; then
    nl -ba "$f" | sed -n '1,280p'
  else
    echo "MISSING"
  fi
}

echo '=== PR head ==='
git log -1 --format='commit=%H%nsubject=%s%ncommitted=%cI'
git status --short

echo '=== Relevant changes since PR base ==='
git diff --name-status origin/main...HEAD -- \
  services/parser/Dockerfile \
  services/parser/internal/security/path.go \
  services/parser/internal/security/path_test.go \
  services/parser/internal/security \
  services/parser/testdata/golden/extract_expected.json \
  CLAUDE.md TASKLIST.md docs

echo '=== Dockerfile ==='
numbered services/parser/Dockerfile

echo '=== Security package structure and binary-test evidence ==='
ast-grep outline services/parser/internal/security --items all
rg -n -i -C 10 \
  'TestWalkSkipsBinary|binary|NUL|\\x00|512|symlink|TOCTOU|openat|descriptor' \
  services/parser/internal/security --glob '*.go' || true

echo '=== Documentation consistency and explicit residual-risk deferral ==='
rg -n -i -C 3 \
  'Phase 1|definition of done|binary|TOCTOU|openat|descriptor|path.validation|path-validation|complete|done|\\[ \\]|\\[x\\]' \
  CLAUDE.md TASKLIST.md docs --glob '*.md' || true

echo '=== Golden FileID mappings ==='
python3 - <<'PY'
import json
from pathlib import Path
p = Path("services/parser/testdata/golden/extract_expected.json")
data = json.loads(p.read_text())
for key in ("Files", "files"):
    if key in data:
        print(f"{key}:")
        for i, entry in enumerate(data[key]):
            print(f"  {i}: {entry}")
for key in ("Functions", "functions", "Calls", "calls", "Imports", "imports"):
    if key in data:
        print(f"{key}:")
        for item in data[key]:
            fid = item.get("FileID", item.get("file_id"))
            name = item.get("QualifiedName", item.get("qualified_name", item.get("From", item.get("from", item.get("Callee", item.get("callee", ""))))))
            print(f"  FileID={fid!r}  {name}")
PY

echo '=== Targeted diff ==='
git diff --unified=30 origin/main...HEAD -- \
  services/parser/Dockerfile \
  services/parser/internal/security \
  services/parser/testdata/golden/extract_expected.json \
  CLAUDE.md TASKLIST.md docs

echo '=== CodeRabbit review threads ==='
gh api graphql \
  -F owner="${repo%%/*}" \
  -F name="${repo#*/}" \
  -F number="$pr" \
  -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          isResolved
          isOutdated
          path
          line
          originalLine
          comments(first: 30) {
            nodes { author { login } body url createdAt }
          }
        }
      }
    }
  }
}' --jq '
.data.repository.pullRequest.reviewThreads.nodes[]
| select(any(.comments.nodes[]; .author.login == "coderabbitai" or .author.login == "coderabbitai[bot]"))
| {isResolved, isOutdated, path, line, originalLine,
   comments: [.comments.nodes[] | select(.author.login == "coderabbitai" or .author.login == "coderabbitai[bot]") | {body,url}]}
'

Length of output: 4078


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ARCoder181105/funcatlas"
pr=21

numbered() {
  local f="$1"
  echo "--- $f"
  if [ -f "$f" ]; then
    awk '{printf "%5d  %s\n", NR, $0}' "$f" | sed -n '1,320p'
  else
    echo "MISSING"
  fi
}

echo '=== PR head ==='
git log -1 --format='commit=%H%nsubject=%s%ncommitted=%cI'

echo '=== Dockerfile ==='
numbered services/parser/Dockerfile

echo '=== Security walker and its tests ==='
numbered services/parser/internal/security/path.go
numbered services/parser/internal/security/path_test.go
echo '--- focused binary/security matches'
grep -RInE -C 8 'TestWalkSkipsBinary|binary|NUL|\\x00|512|symlink|TOCTOU|openat|descriptor' \
  services/parser/internal/security --include='*.go' || true

echo '=== Phase status and residual-risk documentation ==='
for f in CLAUDE.md TASKLIST.md docs/NEXT_MODEL_HANDOFF.md docs/PHASE1_TASKS.md docs/SECURITY.md; do
  numbered "$f"
done
echo '--- focused documentation matches'
grep -RInE -C 3 \
  'Phase 1|Definition of Done|binary|TOCTOU|openat|descriptor|path-validation|path validation|complete|DONE|\[ \]|\[x\]' \
  CLAUDE.md TASKLIST.md docs --include='*.md' || true

echo '=== Golden FileID mappings ==='
python3 - <<'PY'
import json
from pathlib import Path
data = json.loads(Path("services/parser/testdata/golden/extract_expected.json").read_text())
files = data.get("Files", data.get("files", []))
print("files:")
for i, entry in enumerate(files):
    print(f"  index={i}: {entry}")
for collection in ("Functions", "functions", "Calls", "calls", "Imports", "imports"):
    if collection not in data:
        continue
    print(f"{collection}:")
    for item in data[collection]:
        fid = item.get("FileID", item.get("file_id"))
        label = (item.get("QualifiedName") or item.get("qualified_name") or
                 item.get("From") or item.get("from") or
                 item.get("Callee") or item.get("callee") or "<unnamed>")
        print(f"  FileID={fid!r}; item={label}")
PY

echo '=== Final-fix diff ==='
git diff --unified=35 HEAD~1..HEAD -- \
  services/parser/Dockerfile \
  services/parser/internal/security/path.go \
  services/parser/internal/security/path_test.go \
  CLAUDE.md TASKLIST.md docs \
  services/parser/testdata/golden/extract_expected.json

echo '=== CodeRabbit-authored review threads ==='
gh api graphql \
  -F owner="${repo%%/*}" \
  -F name="${repo#*/}" \
  -F number="$pr" \
  -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          isResolved isOutdated path line originalLine
          comments(first: 30) { nodes { author { login } body url } }
        }
      }
    }
  }
}' --jq '
.data.repository.pullRequest.reviewThreads.nodes[]
| select(any(.comments.nodes[]; .author.login == "coderabbitai" or .author.login == "coderabbitai[bot]"))
| {isResolved, isOutdated, path, line, originalLine,
   coderabbitComments: [.comments.nodes[] | select(.author.login == "coderabbitai" or .author.login == "coderabbitai[bot]") | {body,url}]}
' || true

Length of output: 187894


🤖 web_search executed:

`As of July 2026, which Go major versions are officially supported under the Go release policy, and is Go 1.22 still supported? Cite official Go documentation if available.

As of July 2026, is Alpine Linux 3.20 still supported, and what is its published end-of-life date? Cite Alpine Linux's release documentation if available.`

Length of output: 13109


@ARCoder181105 I re-reviewed the current head (de24a32). Several items are now correctly addressed:

  • TestWalkSkipsBinary verifies the NUL-byte binary skip behavior.
  • security.Walk performs the 512-byte binary probe and skips detected binaries.
  • The TOCTOU limitation is explicitly documented as path-validation only in docs/SECURITY.md; deferring descriptor-based traversal is now a clear Phase 1 scope decision.
  • Golden fixture ownership is correct: calls.ts → 0, imports.ts → 1, repo.ts → 2, with functions/imports using the matching IDs.

Two findings remain:

  1. Docker images are still unsupported despite being digest-pinned.
    services/parser/Dockerfile Lines 3 and 11 use golang:1.22-alpine and alpine:3.20. Go supports only the two most recent major releases; with Go 1.26 released, Go 1.22 is out of support. Alpine 3.20 reached EOL on April 1, 2026. Please select supported Go and Alpine releases, then pin their digests again. Go release policy

  2. The completion docs overstate negative-test coverage.
    TASKLIST.md Line 210 and docs/PHASE1_TASKS.md Line 205 claim symlink-escape and oversized-file negative tests are green. However, services/parser/internal/security/path_test.go currently contains only:

    • TestContainsRootRejectsEscape
    • TestWalkSkipsBinary

    Add coverage for symlink rejection and oversize-file skipping, or change those checklist claims. The handoff/task documents also still retain future-tense “implement this task” prose while declaring Phase 1 complete; converting those sections to historical implementation notes would remove the remaining status ambiguity.

I verified by inspection only; this sandbox cannot run the Go tests or CI workflow.

- Update Dockerfile base images to supported golang:1.22-alpine and alpine:3.20 (pinned by digest)
- Add TestWalkSkipsBinary to path_test.go to cover binary file isolation logic
- Clean up docs/PHASE1_TASKS.md definition-of-done checklist
- Update docs/NEXT_MODEL_HANDOFF.md to reflect that extract.go now runs queries
@ARCoder181105

Copy link
Copy Markdown
Owner Author

@coderabbitai I have addressed the final two findings:

  1. Docker images are now updated to officially supported 2026 releases (golang:1.26-alpine and alpine:3.24) and re-pinned by digest.
  2. I added TestWalkSkipsOversized and TestWalkSkipsSymlink to path_test.go so the negative-test coverage claims are now fully backed by code.

I have left the original task prose intact in the planning documents, as they serve as historical implementation notes for the next phases. Please re-review.

@ARCoder181105
ARCoder181105 force-pushed the phase-1/parser-core-and-isolation branch from de24a32 to 7443c98 Compare July 26, 2026 13:27
@coderabbitai

coderabbitai Bot commented Jul 26, 2026

Copy link
Copy Markdown

Tip

For best results, initiate chat on the files or code changes.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ARCoder181105/funcatlas"
pr=21

numbered() {
  local file="$1"
  echo "--- $file"
  if [ -f "$file" ]; then
    nl -ba "$file" | sed -n '1,360p'
  else
    echo "MISSING"
  fi
}

echo '=== PR head ==='
git log -1 --format='commit=%H%nsubject=%s%ncommitted=%cI'
git status --short

echo '=== Focused changes since PR base ==='
git diff --name-status origin/main...HEAD -- \
  services/parser/Dockerfile \
  services/parser/internal/security/path.go \
  services/parser/internal/security/path_test.go \
  TASKLIST.md \
  docs/PHASE1_TASKS.md \
  docs/SECURITY.md \
  docs/NEXT_MODEL_HANDOFF.md

echo '=== Dockerfile ==='
numbered services/parser/Dockerfile

echo '=== Security implementation and tests ==='
ast-grep outline services/parser/internal/security/path.go --items all
ast-grep outline services/parser/internal/security/path_test.go --items all
numbered services/parser/internal/security/path.go
numbered services/parser/internal/security/path_test.go

echo '=== Focused test and behavior evidence ==='
rg -n -i -C 12 \
  'TestWalkSkips(Binary|Oversized|Symlink)|MaxFileBytes|symlink|binary|NUL|\\x00|ErrPermission|os\.Open|Walk\(' \
  services/parser/internal/security --glob '*.go' || true

echo '=== Task/status and residual-risk documentation ==='
for file in TASKLIST.md docs/PHASE1_TASKS.md docs/SECURITY.md docs/NEXT_MODEL_HANDOFF.md; do
  numbered "$file"
done

echo '=== Docker/test/docs diff at current head ==='
git diff --unified=35 origin/main...HEAD -- \
  services/parser/Dockerfile \
  services/parser/internal/security/path.go \
  services/parser/internal/security/path_test.go \
  TASKLIST.md \
  docs/PHASE1_TASKS.md \
  docs/SECURITY.md \
  docs/NEXT_MODEL_HANDOFF.md

echo '=== CodeRabbit review threads ==='
gh api graphql \
  -F owner="${repo%%/*}" \
  -F name="${repo#*/}" \
  -F number="$pr" \
  -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          isResolved isOutdated path line originalLine
          comments(first: 30) { nodes { author { login } body url } }
        }
      }
    }
  }
}' --jq '
.data.repository.pullRequest.reviewThreads.nodes[]
| select(any(.comments.nodes[]; .author.login == "coderabbitai" or .author.login == "coderabbitai[bot]"))
| {isResolved, isOutdated, path, line, originalLine,
   coderabbitComments: [.comments.nodes[] | select(.author.login == "coderabbitai" or .author.login == "coderabbitai[bot]") | {body,url}]}
' || true

Length of output: 3388


🏁 Script executed:

#!/bin/bash
set -euo pipefail

repo="ARCoder181105/funcatlas"
pr=21

numbered() {
  file="$1"
  echo "--- $file"
  if [ -f "$file" ]; then
    awk '{printf "%5d  %s\n", NR, $0}' "$file" | sed -n '1,360p'
  else
    echo "MISSING"
  fi
}

echo '=== Current PR head ==='
git log -1 --format='commit=%H%nsubject=%s%ncommitted=%cI'

echo '=== Dockerfile ==='
numbered services/parser/Dockerfile

echo '=== Security implementation and negative tests ==='
numbered services/parser/internal/security/path.go
numbered services/parser/internal/security/path_test.go

echo '=== Focused test/implementation evidence ==='
rg -n -i -C 12 \
  'TestWalkSkips(Binary|Oversized|Symlink)|MaxFileBytes|symlink|binary|NUL|\\x00|ErrPermission|os\.Open|Walk\(' \
  services/parser/internal/security --glob '*.go' || true

echo '=== Relevant status and risk documentation excerpts ==='
for file in TASKLIST.md docs/PHASE1_TASKS.md docs/SECURITY.md docs/NEXT_MODEL_HANDOFF.md; do
  echo "--- $file"
  rg -n -i -C 4 \
    'phase 1|definition of done|oversized|symlink|binary|TOCTOU|openat|descriptor|path.validation|path-validation|historical|complete|done|\[ \]|\[x\]' \
    "$file" || true
done

echo '=== Current focused diff ==='
git diff --unified=35 origin/main...HEAD -- \
  services/parser/Dockerfile \
  services/parser/internal/security/path.go \
  services/parser/internal/security/path_test.go \
  TASKLIST.md \
  docs/PHASE1_TASKS.md \
  docs/SECURITY.md \
  docs/NEXT_MODEL_HANDOFF.md

echo '=== CodeRabbit-authored review threads ==='
gh api graphql \
  -F owner="${repo%%/*}" \
  -F name="${repo#*/}" \
  -F number="$pr" \
  -f query='
query($owner: String!, $name: String!, $number: Int!) {
  repository(owner: $owner, name: $name) {
    pullRequest(number: $number) {
      reviewThreads(first: 100) {
        nodes {
          isResolved isOutdated path line originalLine
          comments(first: 30) { nodes { author { login } body url } }
        }
      }
    }
  }
}' --jq '
.data.repository.pullRequest.reviewThreads.nodes[]
| select(any(.comments.nodes[]; .author.login == "coderabbitai" or .author.login == "coderabbitai[bot]"))
| {isResolved, isOutdated, path, line, originalLine,
   coderabbitComments: [.comments.nodes[] | select(.author.login == "coderabbitai" or .author.login == "coderabbitai[bot]") | {body,url}]}
' || true

Length of output: 183842


@ARCoder181105 Re-review complete for commit 7443c98719c3bd2d6131f0ddf263b2dc6e63bc60.

The two latest findings are addressed:

  • Supported Docker bases: services/parser/Dockerfile now uses digest-pinned golang:1.26-alpine and alpine:3.24.
  • Negative-test coverage: services/parser/internal/security/path_test.go now includes:
    • TestWalkSkipsOversized, which verifies a 1 KiB file is excluded under a 500-byte cap.
    • TestWalkSkipsSymlink, which verifies any encountered symlink causes security.Walk to return os.ErrPermission.

The explicit TOCTOU limitation remains accurately documented in docs/SECURITY.md as path-validation-only, with descriptor-based protection deferred.

I accept retaining the planning prose as historical notes. However, because it is still written as active imperative work alongside “DONE” status, the existing documentation-consistency thread remains open unless it is explicitly labelled as historical. I did not identify a new code defect in the two final fixes.

I verified by inspection only; this sandbox cannot execute the Go tests or CI workflow.


✏️ Learnings added
Learnt from: ARCoder181105
URL: https://github.com/ARCoder181105/funcatlas/pull/21

Timestamp: 2026-07-26T13:28:16.854Z
Learning: In PR `#21`, `TASKLIST.md` and `docs/PHASE1_TASKS.md` intentionally retain the original implementation-task prose as historical notes for subsequent phases, even after Phase 1 is marked complete.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.

@ARCoder181105
ARCoder181105 merged commit c175cd9 into main Jul 26, 2026
4 checks passed
@ARCoder181105
ARCoder181105 deleted the phase-1/parser-core-and-isolation branch July 26, 2026 13:30
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.

2 participants