Skip to content

Commit 10008ff

Browse files
authored
Merge pull request #1 from tae2089/refactor/trim-peripheral-features
Trim peripheral features, improve search, and fix review findings
2 parents a5e8a48 + cb7bcd8 commit 10008ff

79 files changed

Lines changed: 1043 additions & 6089 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ jobs:
3030
- name: Run go vet
3131
run: make vet
3232

33+
- name: Run go test
34+
run: CGO_ENABLED=1 go test -tags "fts5" ./... -count=1
35+
3336
- name: Build release binaries
3437
run: make build
3538

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ pyproject.toml
2727
/web/wiki/dist/
2828
/web/wiki/node_modules/
2929
search-retrieval.md
30+
_workspace/

cmd/ccg/main_postgres_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ func TestRunMigrations_PostgresDownRestoresNullableColumns(t *testing.T) {
157157
t.Fatalf("run down migration: %v", err)
158158
}
159159

160-
var version migrateSchemaVersion
160+
var version migration.MigrationSchemaVersion
161161
if err := db.Table("schema_migrations").First(&version).Error; err != nil {
162162
t.Fatalf("load schema version: %v", err)
163163
}
@@ -190,7 +190,7 @@ func TestRunMigrations_PostgresDownFromVersionThreeDropsPolicyTables(t *testing.
190190
t.Fatalf("run down migration: %v", err)
191191
}
192192

193-
var version migrateSchemaVersion
193+
var version migration.MigrationSchemaVersion
194194
if err := db.Table("schema_migrations").First(&version).Error; err != nil {
195195
t.Fatalf("load schema version: %v", err)
196196
}

docker-compose.langfuse.yaml

Lines changed: 0 additions & 178 deletions
This file was deleted.

internal/analysis/changes/git.go

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,10 @@ func NewExecGitClient() *ExecGitClient {
3737
// @requires repoDir points to a valid git working tree
3838
// @ensures returned file paths are trimmed and exclude blank lines
3939
func (g *ExecGitClient) ChangedFiles(ctx context.Context, repoDir, baseRef string) ([]string, error) {
40-
out, err := runGitLimited(ctx, repoDir, []string{"diff", "--name-only", baseRef})
40+
if err := validateBaseRef(baseRef); err != nil {
41+
return nil, err
42+
}
43+
out, err := runGitLimited(ctx, repoDir, []string{"-c", "core.quotePath=false", "diff", "--name-only", baseRef, "--"})
4144
if err != nil {
4245
return nil, trace.Wrap(err, "git diff --name-only")
4346
}
@@ -66,7 +69,10 @@ func (g *ExecGitClient) ChangedFiles(ctx context.Context, repoDir, baseRef strin
6669
// @requires repoDir points to a valid git working tree
6770
// @ensures each returned hunk has a file path and inclusive start/end lines
6871
func (g *ExecGitClient) DiffHunks(ctx context.Context, repoDir, baseRef string, paths []string) ([]Hunk, error) {
69-
args := []string{"diff", "-U0", baseRef, "--"}
72+
if err := validateBaseRef(baseRef); err != nil {
73+
return nil, err
74+
}
75+
args := []string{"-c", "core.quotePath=false", "diff", "-U0", baseRef, "--"}
7076
args = append(args, paths...)
7177
out, err := runGitLimited(ctx, repoDir, args)
7278
if err != nil {
@@ -98,6 +104,19 @@ func (g *ExecGitClient) DiffHunks(ctx context.Context, repoDir, baseRef string,
98104
return hunks, nil
99105
}
100106

107+
// validateBaseRef rejects base revisions that git would parse as command options.
108+
// @intent block git argument injection through the caller-supplied base ref, which sits
109+
// before the "--" separator and would otherwise be interpreted as a diff flag.
110+
func validateBaseRef(baseRef string) error {
111+
if baseRef == "" {
112+
return fmt.Errorf("base ref must not be empty")
113+
}
114+
if strings.HasPrefix(baseRef, "-") {
115+
return fmt.Errorf("invalid base ref %q: must not start with '-'", baseRef)
116+
}
117+
return nil
118+
}
119+
101120
// runGitLimited runs a git subcommand with the default output size cap.
102121
// @intent share a single bounded git invocation helper across diff operations
103122
func runGitLimited(ctx context.Context, repoDir string, args []string) ([]byte, error) {

internal/analysis/changes/git_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,46 @@ func TestGitClient_ChangedFiles(t *testing.T) {
2929
}
3030
}
3131

32+
func TestGitClient_RejectsOptionLikeBaseRef(t *testing.T) {
33+
dir := initTestRepo(t)
34+
writeFile(t, dir, "hello.go", "package main\n")
35+
gitCommit(t, dir, "initial")
36+
37+
git := NewExecGitClient()
38+
for _, base := range []string{"--output=/tmp/pwned", "-U9999", "--no-index"} {
39+
if _, err := git.ChangedFiles(context.Background(), dir, base); err == nil {
40+
t.Errorf("ChangedFiles accepted option-like base %q", base)
41+
}
42+
if _, err := git.DiffHunks(context.Background(), dir, base, []string{"hello.go"}); err == nil {
43+
t.Errorf("DiffHunks accepted option-like base %q", base)
44+
}
45+
}
46+
}
47+
48+
func TestGitClient_ChangedFiles_NonASCIIPath(t *testing.T) {
49+
dir := initTestRepo(t)
50+
writeFile(t, dir, "한글.go", "package main\n")
51+
gitCommit(t, dir, "initial")
52+
writeFile(t, dir, "한글.go", "package main\n\nfunc Hello() {}\n")
53+
54+
git := NewExecGitClient()
55+
files, err := git.ChangedFiles(context.Background(), dir, "HEAD")
56+
if err != nil {
57+
t.Fatal(err)
58+
}
59+
if len(files) != 1 || files[0] != "한글.go" {
60+
t.Fatalf("expected unquoted 한글.go, got %v", files)
61+
}
62+
63+
hunks, err := git.DiffHunks(context.Background(), dir, "HEAD", []string{"한글.go"})
64+
if err != nil {
65+
t.Fatal(err)
66+
}
67+
if len(hunks) == 0 || hunks[0].FilePath != "한글.go" {
68+
t.Fatalf("expected hunk for unquoted 한글.go, got %+v", hunks)
69+
}
70+
}
71+
3272
func TestGitClient_DiffHunks(t *testing.T) {
3373
dir := initTestRepo(t)
3474
writeFile(t, dir, "hello.go", "package main\n\nfunc Old() {}\n")

internal/analysis/fallback/service.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,17 @@ func (s *Service) FindSuspectsPage(ctx context.Context, opts Options) (Result, e
8686
results := make([]SuspectEdge, 0, len(edges))
8787
for _, edge := range edges {
8888
source, err := s.store.GetNodeByID(ctx, edge.FromNodeID)
89-
if err != nil || source == nil {
89+
if err != nil {
9090
return Result{}, err
9191
}
9292
target, err := s.store.GetNodeByID(ctx, edge.ToNodeID)
93-
if err != nil || target == nil {
93+
if err != nil {
9494
return Result{}, err
9595
}
96+
// A dangling edge (endpoint node missing) must not silently drop the whole page.
97+
if source == nil || target == nil {
98+
continue
99+
}
96100
sourceAnn, err := s.store.GetAnnotation(ctx, source.ID)
97101
if err != nil {
98102
return Result{}, err

internal/analysis/fallback/service_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,44 @@ func TestSuspectFallbackEdges_FlagsDisjointIntentAndDomainRule(t *testing.T) {
6363
}
6464
}
6565

66+
func TestSuspectFallbackEdges_SkipsEdgeWithMissingEndpointInsteadOfDroppingPage(t *testing.T) {
67+
db := setupFallbackDB(t)
68+
ctx := context.Background()
69+
store := gormstore.New(db)
70+
71+
source := model.Node{QualifiedName: "pkg.A", Kind: model.NodeKindFunction, Name: "A", FilePath: "a.go", StartLine: 1, EndLine: 2, Language: "go"}
72+
target := model.Node{QualifiedName: "pkg.B", Kind: model.NodeKindFunction, Name: "B", FilePath: "b.go", StartLine: 1, EndLine: 2, Language: "go"}
73+
if err := store.UpsertNodes(ctx, []model.Node{source, target}); err != nil {
74+
t.Fatal(err)
75+
}
76+
sourceNode, _ := store.GetNode(ctx, "pkg.A")
77+
targetNode, _ := store.GetNode(ctx, "pkg.B")
78+
if err := store.UpsertEdges(ctx, []model.Edge{
79+
// dangling edge: endpoint node id does not exist
80+
{FromNodeID: 99999, ToNodeID: targetNode.ID, Kind: model.EdgeKindFallbackCalls, Fingerprint: "a-dangling"},
81+
{FromNodeID: sourceNode.ID, ToNodeID: targetNode.ID, Kind: model.EdgeKindFallbackCalls, Fingerprint: "b-valid"},
82+
}); err != nil {
83+
t.Fatal(err)
84+
}
85+
if err := store.UpsertAnnotation(ctx, &model.Annotation{NodeID: sourceNode.ID, Summary: "auth", Tags: []model.DocTag{{Kind: model.TagIntent, Value: "verify credentials", Ordinal: 0}}}); err != nil {
86+
t.Fatal(err)
87+
}
88+
if err := store.UpsertAnnotation(ctx, &model.Annotation{NodeID: targetNode.ID, Summary: "billing", Tags: []model.DocTag{{Kind: model.TagIntent, Value: "render invoice", Ordinal: 0}}}); err != nil {
89+
t.Fatal(err)
90+
}
91+
92+
results, err := New(db, store).FindSuspects(ctx, Options{})
93+
if err != nil {
94+
t.Fatal(err)
95+
}
96+
if len(results) != 1 {
97+
t.Fatalf("dangling edge must be skipped, not drop the whole page: got %d results", len(results))
98+
}
99+
if results[0].Source.QualifiedName != "pkg.A" {
100+
t.Fatalf("expected surviving valid edge, got %+v", results[0])
101+
}
102+
}
103+
66104
func TestSuspectFallbackEdges_IgnoresOverlappingAnnotationContext(t *testing.T) {
67105
db := setupFallbackDB(t)
68106
ctx := context.Background()

internal/analysis/flows/flows.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ func (t *Tracer) TraceFlowBounded(ctx context.Context, startNodeID uint, opts Tr
143143
Truncated: truncated,
144144
MaxNodes: opts.MaxNodes,
145145
ReturnedNodes: len(members),
146-
ContainsFallbackCalls: containsFallbackCalls,
146+
ContainsFallbackCalls: containsFallbackCalls,
147147
FallbackEdgesCount: fallbackEdges,
148148
}, nil
149149
}

internal/annotation/normalizer.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ func stripBlockDelimiters(text string, language string) string {
8484
}
8585

8686
// stripPythonDocstringDelimiters removes triple-quote wrappers from a Python docstring body.
87-
// @intent expose the raw docstring text by trying both """ and ''' triple-quote forms.
87+
// @intent expose the raw docstring text by trying both """ and ' triple-quote forms.
8888
func stripPythonDocstringDelimiters(text string) (string, bool) {
8989
for _, quote := range []string{"\"\"\"", "'''"} {
9090
if stripped, ok := stripPythonQuotedString(text, quote); ok {

0 commit comments

Comments
 (0)