Skip to content

detect: Stage 1 sensitive-dir check silently drops legitimate source under secrets/ and credentials/ (follow-up to #1225) #1943

Description

@HerenderKumar

Summary

The Stage 1 sensitive-directory check in detect.py silently drops every file beneath a directory named secrets/, .secrets/, or credentials/ — including legitimate programming-language source that just happens to live in a package with that name. The files vanish from the graph with no trace and no way to override.

This is the same false-positive class as #1225 (which fixed the Stage 3 keyword heuristic), but at the directory level, which #1225 did not touch.

Repro

repo/
  internal/secrets/vault.go        # real Go source package
  app/services/credentials/manager.py  # real Python module
  secrets/db.json                  # actual credential store

internal/secrets/vault.go and credentials/manager.py are dropped from the graph. A quick check:

from pathlib import Path
from graphify.detect import _is_sensitive
_is_sensitive(Path("internal/secrets/vault.go"))          # True  (wrong — this is source)
_is_sensitive(Path("app/services/credentials/manager.py"))# True  (wrong — this is source)
_is_sensitive(Path("secrets/db.json"))                    # True  (correct — real secret store)

secrets/ and credentials/ are just as often real source packages (Go internal/secrets, a credentials/ service module) as credential stores, so pruning them wholesale by name loses legitimate source.

Expected

Genuine programming-language source under an ambiguous secrets//credentials/ dir should be graphed, exactly the way Stage 3 already refuses to drop a .py/.rb source file on a keyword hit (#1225). Secret-prone data/config files (.env, .json, .yaml, key material) inside those dirs, and dedicated credential-store dirs (.ssh, .gnupg, .aws, .gcloud), must stay flagged.

Proposed fix

Give Stage 1 the same source-code carve-out Stage 3 has: split _SENSITIVE_DIRS into dedicated credential stores (always skipped) and ambiguous bare-name dirs (skip everything except genuine source, via the existing classify_file(...) == CODE and ext not in _SECRET_PRONE_DATA_EXTS predicate). Credential stores keep their protection and .graphifyinclude still cannot rescue them.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions