SIGN IN SIGN UP

engine: detection, which is what makes af init worth running

internal/detect derives a manifest draft from a repository by reading files.
Twelve analyzers cover Node and its frameworks, Python with Django, FastAPI,
Flask, and Celery, Go, Rails and Sidekiq, Dockerfiles, Compose, Procfiles,
migration tools, environment variables, third party SDKs, and schedules.

Two constraints shape the whole package.

The repository is untrusted input, so detection never executes anything from
it. No npm install, no go run, no evaluating a config file that happens to be
JavaScript. Everything is parsing, every parser is bounded, symlinks are not
followed, and the walk has limits on file size, total bytes, file count, and
wall time. A budget that runs out returns partial results with an explicit
note, because an af init that appears to hang is worse than one that says what
it did not finish.

Detection is deterministic. af init writes a manifest that gets committed, and
one that shuffles on every run is unusable in review, so findings are sorted
before merging and a test runs the same tree ten times and compares.

The merger's rule: high confidence goes into the draft silently, anything less
becomes a question, and a disagreement between analyzers always becomes a
question, because a conflict is exactly where a silent choice is most likely to
be wrong. Every finding names the file that produced it, so a user can check
the reasoning rather than trust it.

The third party catalog is the part a user could not write themselves. It maps
an SDK to its hostnames and to a default egress mode, and the modes are
judgements stated in the manifest as notes: Stripe gets sandbox because it has
a real one, mail providers get capture because "allow" means a preview
environment emails a real customer, analytics and error reporting get block
because they would pollute production reporting, and model providers get mock
because a preview run should cost nothing and answer the same way twice.

Compose parsing reads the container side of a port mapping rather than the
host side, since "8080:3000" means the application binds 3000, and reading the
wrong half produces an environment that never becomes ready. Database and
queue images are recognised as infrastructure rather than services to build,
including behind a registry prefix.

Dotenv files are read for names only, never values. An example file sometimes
contains a real credential by accident, and reading the value would carry it
into a finding, then an event, then a log. A test plants one and asserts it
appears nowhere.

Failure paths covered:
  a transitive dependency creates a rule: TestRun_SkipsDependencyAndBuildDirectories
  a test fixture is mistaken for the app: TestRun_SkipsTestAndExampleDockerfiles
  one malformed file loses the repository: TestRun_MalformedPackageJsonIsReportedNotFatal
  an analyzer fails: TestRun_AnAnalyzerThatFailsDoesNotLoseTheOthers
  the budget runs out: TestRun_ReportsPartialResultsWhenTheBudgetRunsOut
  a host port is read as the container port: TestRun_ComposePublishesTheContainerPortNotTheHostPort
  sources disagree about a port: TestRun_AsksWhenSourcesDisagreeAboutAPort
  output shuffles between runs: TestRun_IsDeterministic
  a credential in an example file leaks: TestRun_NeverReadsAValueFromAnExampleFile
  a huge checked in file: TestRun_LargeFilesAreSkippedAndReported

Fuzzed 416,000 executions across package.json, Dockerfile, and compose inputs
with no crashes. Coverage 80.8 percent.

Signed-off-by: Vir Sanghavi <Virrsanghavi@gmail.com>
V
Vir Sanghavi committed
0615766bb9b6728b4ca2d9525a8632a1ef4cf31e
Parent: 318f08e