Skip to content

Commit 69b677d

Browse files
authored
Merge pull request #175 from NDDev-OpenNetwork/fix/discovery-hidden-dirs
fix: skip hidden directories in discovery; read-only remote observation for quarantine
2 parents 1b9a57e + 150b6fc commit 69b677d

7 files changed

Lines changed: 97 additions & 11 deletions

File tree

‎.gds/bundle.lock.yaml‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,14 @@ bundle:
55
version: "0.9.6-dev"
66
release_sequence: 0
77
channel: "development"
8-
source_tree_digest: "sha256:6799d517ad06faba9cc1edc3830dd54d0a890f3573bc1f60a26232f5d1926524"
9-
digest: "sha256:db7dae4282ef3d69f0375c9e54feada9dc11f219d64e591a76559883ea598f0e"
8+
source_tree_digest: "sha256:b9d572eb73bb14ae8ede20dfc1e9317046dcb544270eff95153746f93f094820"
9+
digest: "sha256:a45453995b649d082b39753c1d7eff869d2dcad5180532cb14f85435fae2a7fa"
1010

1111
projection:
12-
input_digest: "sha256:37d63f73feba8549ec22aa97b81b7cc0d53b701d73b36661625c0bb61da53998"
13-
output_digest: "sha256:508542eaec283ca3e14bb78c495c0c52a45ebb85b24cce2e104f8655ad1b0bb1"
12+
input_digest: "sha256:90af33f4abbb808f5567e074347f17822cc610029e11a835fb5a8918c376ec9b"
13+
output_digest: "sha256:080add7de51702df727bb8f1b770dcd5fd8343000d8b249af94a7b342a0a240b"
1414
files:
1515
- path: ".gds/compiled-policy.json"
1616
digest: "sha256:211668dd85e9d4bd3f547a1ea0cc9b1a5f486c64bde02a328b53dc3ef665c9fd"
1717
- path: ".github/workflows/gds-ci.yml"
18-
digest: "sha256:2e18aafadceafafab54dbf21fd0f68b50c9618aed05d8f2eb39e161ef999c287"
18+
digest: "sha256:eef6659ecb3cd40914b73fde9856ad2bfa96f106ceac52f8c2fda0ef4fc00a79"

‎.github/workflows/gds-ci.yml‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# GENERATED FILE - DO NOT EDIT DIRECTLY
22
# generator: gds
33
# bundle: 0.9.6-dev
4-
# source-tree-digest: sha256:6799d517ad06faba9cc1edc3830dd54d0a890f3573bc1f60a26232f5d1926524
5-
# input-digest: sha256:37d63f73feba8549ec22aa97b81b7cc0d53b701d73b36661625c0bb61da53998
4+
# source-tree-digest: sha256:b9d572eb73bb14ae8ede20dfc1e9317046dcb544270eff95153746f93f094820
5+
# input-digest: sha256:90af33f4abbb808f5567e074347f17822cc610029e11a835fb5a8918c376ec9b
66
# output-digest: sha256:b9bf3d0c64c0fb371596e7d090e82e62aebbfde91929115fc15fb28644e4fd38
77
# edit-source:
88
# - .gds/repository.yaml

‎core/discovery/local.go‎

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,9 +306,15 @@ func pathDepth(relative string) int {
306306
}
307307

308308
func excludedDirectory(name string) bool {
309+
// Hidden directories other than a repository's own .git boundary are tool
310+
// state, caches, or generated fixtures (".tmp", ".idea", ".venv", ...) —
311+
// never portfolio checkouts. Scanning them manufactures anchor findings
312+
// for synthetic trees and burns time on ignored content.
313+
if name != ".git" && strings.HasPrefix(name, ".") {
314+
return true
315+
}
309316
switch name {
310-
case ".cache", ".idea", ".pytest_cache", ".ruff_cache", ".tox", ".venv",
311-
"__pycache__", "node_modules", "target", "vendor":
317+
case "__pycache__", "node_modules", "target", "vendor":
312318
return true
313319
default:
314320
return false

‎core/discovery/local_test.go‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -190,3 +190,33 @@ func TestDiscoverAcceptsIdentityPinnedBySuperprojectAndCheckedOutStandalone(t *t
190190
}
191191
}
192192
}
193+
194+
func TestDiscoverSkipsHiddenDirectoryTrees(t *testing.T) {
195+
t.Parallel()
196+
// Boundaries are reported canonicalized: on macOS t.TempDir() lives under
197+
// /var, which is a symlink to /private/var.
198+
root, err := filepath.EvalSymlinks(t.TempDir())
199+
if err != nil {
200+
t.Fatal(err)
201+
}
202+
plain := filepath.Join(root, "plain")
203+
fixture := filepath.Join(root, ".tmp", "native-linux", "fixture-repo")
204+
for _, path := range []string{plain, fixture} {
205+
if err := os.MkdirAll(path, 0o755); err != nil {
206+
t.Fatal(err)
207+
}
208+
if output, err := exec.Command("git", "init", "-q", path).CombinedOutput(); err != nil {
209+
t.Fatalf("git init %s: %v\n%s", path, err, output)
210+
}
211+
}
212+
213+
result, err := newTestDiscovery(t).Discover(
214+
context.Background(), root, Options{MaxDepth: 8, MaxRepositories: 10, Concurrency: 2},
215+
)
216+
if err != nil {
217+
t.Fatalf("Discover() error = %v", err)
218+
}
219+
if len(result.Boundaries) != 1 || result.Boundaries[0].Path != plain {
220+
t.Fatalf("boundaries = %#v, want only %s", result.Boundaries, plain)
221+
}
222+
}

‎core/providers/git/handoff.go‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,10 @@ func (runner *MutationRunner) observeRemoteRef(
362362
) (string, error) {
363363
result, err := runner.runWithEnvironment(
364364
ctx, root, map[int]struct{}{0: {}}, nil,
365-
"-c", "protocol.allow=never", "-c", "protocol.file.allow=always",
365+
"-c", "protocol.allow=never",
366+
"-c", "protocol.file.allow=always",
367+
"-c", "protocol.https.allow=always",
368+
"-c", "protocol.ssh.allow=always",
366369
"ls-remote", "--refs", remoteURL, remoteRef,
367370
)
368371
if err != nil {

‎core/providers/git/quarantine.go‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,11 @@ func (runner *MutationRunner) observeCheckoutForQuarantine(
168168
status.Worktrees[0].Locked || status.Worktrees[0].Prunable {
169169
return CheckoutQuarantineEvidence{}, errors.New("checkout is not clean, current, and exclusive")
170170
}
171-
remoteURL, err := runner.validatedPushURL(ctx, physical, "origin")
171+
// Quarantine only reads the remote (ls-remote below) to prove the checkout's
172+
// commits are published; it never pushes. The fetch-side URL is therefore
173+
// the right one to observe and network transports are allowed — the
174+
// mutation-only gate (validatedPushURL) does not apply to a read.
175+
_, remoteURL, err := runner.validatedRemoteURL(ctx, physical, "origin")
172176
if err != nil {
173177
return CheckoutQuarantineEvidence{}, err
174178
}

‎core/providers/git/quarantine_test.go‎

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package git
33
import (
44
"context"
55
"crypto/sha256"
6+
"errors"
67
"fmt"
78
"os"
89
"path/filepath"
@@ -75,3 +76,45 @@ func TestQuarantineCheckoutPreservesDirtyRepository(t *testing.T) {
7576
t.Fatalf("dirty work changed: %q %v", content, err)
7677
}
7778
}
79+
80+
func TestQuarantineRemoteValidationAdmitsNetworkTransportsForReadOnlyObservation(t *testing.T) {
81+
client, _ := mutationRepository(t)
82+
runFetchGit(t, client, "remote", "add", "origin", "git@github.com:example/repository.git")
83+
runner, err := NewMutationRunner()
84+
if err != nil {
85+
t.Fatal(err)
86+
}
87+
_, url, err := runner.validatedRemoteURL(context.Background(), client, "origin")
88+
if err != nil {
89+
t.Fatalf("read-only observation must admit the fetch URL: %v", err)
90+
}
91+
if url != "git@github.com:example/repository.git" {
92+
t.Fatalf("url=%q", url)
93+
}
94+
if _, err := runner.validatedPushURL(context.Background(), client, "origin"); !errors.Is(err, ErrNetworkMutationDisabled) {
95+
t.Fatalf("push URL must remain mutation-gated: %v", err)
96+
}
97+
}
98+
99+
func TestQuarantineCheckoutNetworkRemoteFailsAtObservationNotAtTheMutationGate(t *testing.T) {
100+
fixture := fastForwardFixture(t)
101+
runFetchGit(t, fixture.client, "remote", "set-url", "origin", "ssh://127.0.0.1:1/repository.git")
102+
head := stringsTrim(runFetchGit(t, fixture.client, "rev-parse", "HEAD"))
103+
workspaceRoot := filepath.Dir(fixture.client)
104+
stateRoot := t.TempDir()
105+
quarantine := filepath.Join(stateRoot, "quarantine", "checkouts", "repo_fixture", head)
106+
runner, err := NewMutationRunner()
107+
if err != nil {
108+
t.Fatal(err)
109+
}
110+
_, err = runner.QuarantineCheckout(
111+
context.Background(), workspaceRoot, fixture.client, stateRoot, quarantine,
112+
head, "refs/heads/main", fmt.Sprintf("sha256:%x", sha256.Sum256([]byte("x"))),
113+
)
114+
if err == nil {
115+
t.Fatal("an unreachable remote must fail the observation")
116+
}
117+
if errors.Is(err, ErrNetworkMutationDisabled) {
118+
t.Fatalf("read-only remote observation must not hit the mutation gate: %v", err)
119+
}
120+
}

0 commit comments

Comments
 (0)