Skip to content

feat(cli): Add scan defaults and compilation model caching#89

Merged
misonijnik merged 61 commits intomainfrom
misonijnik/rework-compile-and-scan
Apr 16, 2026
Merged

feat(cli): Add scan defaults and compilation model caching#89
misonijnik merged 61 commits intomainfrom
misonijnik/rework-compile-and-scan

Conversation

@misonijnik
Copy link
Copy Markdown
Member

No description provided.

- Remove MarkFlagRequired("output"), default SARIF to project-model/sources/
- Replace temp dir with staging dir inside model cache
- Promote staging to cache via symlink swap after successful scan
- Clean up staging dir on compilation failure
- Update printScanInfo to show "Project model (staging)"
- Add DefaultSarifReportPath and StableProjectModelPath to model_cache.go
- Replace hardcoded "project-model"/"sources"/"opentaint.sarif" in scan.go
- Extract cleanupStaging closure to deduplicate two identical cleanup blocks
- Extract setupPruneTestGlobals helper to deduplicate test boilerplate
- Scan with default output (no --output flag) → SARIF in cache
- Verify cached model directory structure (symlink, SARIF location)
- Scan with no arguments (defaults to current directory)
- Scan pre-compiled model without --output → SARIF in model/sources/
- Prune --dry-run lists cached models
- Prune --yes removes cached models
EnsureParentDir(sarifPath) for the default path
<staging>/project-model/sources/opentaint.sarif was creating
project-model/ inside the staging dir before compile ran.
ValidateCompileInputs then failed with "output directory already
exists". Move EnsureParentDir to after compilation in
CompileAndScan mode.
…output

- Move symlink promotion from post-analysis to post-compilation
- Analysis now runs against the stable cached model path
- printScanInfo shows the final cache path, not the staging path
- Recompute SARIF path after promotion to use stable model path
…al retention

- Skip compilation when a valid cached model exists (project.yaml present)
- Add --recompile flag to force recompilation
- Implement generational retention (N=1): keep current + previous model
  version during promotion to protect concurrent readers
- Third promotion removes the oldest generation automatically
…terference

After promotion or cache reuse, resolve the project-model symlink to
the actual timestamped directory (e.g. project-model-1234567890/).
This pins each scan process to its own model generation so that a
concurrent scan promoting a new version does not redirect the
symlink out from under an in-progress analysis.
…oncurrently

When no cached model exists and a .staging-* directory is present,
another scan process is already compiling. Instead of starting a
redundant compilation, stop with a clear message asking the user
to wait or use --project-model.
… value

ScanMode's zero value is Scan, so when cache reuse check fails,
scanMode remained 0 (Scan) and the CompileAndScan branch was
never entered, leaving absProjectModelPath empty. Use a dedicated
cachedModelReused bool to guard the CompileAndScan fallthrough.
…-model/ dir

Concurrent compilations are prevented by HasStagingDir, so the
symlink-swap and timestamped directories are unnecessary complexity.
Now PromoteStagingToCache simply replaces <cache>/project-model/
directly. Removes ~50 lines of symlink/generation management code.
The positional argument now exclusively accepts a path to project
sources. A new --project-model flag allows passing a pre-compiled
project model directly, replacing the previous auto-detection logic.
…rentDir

Extract the three-way scan mode resolution (explicit model, dry-run,
cache/staging) into a scanConfig struct and resolveScanConfig function.
Replace scattered mutable variables (tempProjectModel, tempLogsDir,
scanMode, projectCachePath, tempProjectModelPath) with a single cfg
value. Consolidate the two EnsureParentDir calls into one placed after
the compilation block, covering both scan-only and compile-and-scan
modes.
Reflect the new scan behavior: source path defaults to current directory,
--output is optional (defaults to cached model dir), compiled models are
cached and reused, --recompile forces recompilation, --project-model
replaces positional arg for pre-compiled models, and prune removes
cached models.
…defaults

Simplify scan command in all translation READMEs to just `opentaint scan`.
Update classes-and-jars-analysis to use --project-model flag.
- Extract activateLoggingForProject() to eliminate repeated
  cache-path-resolution pattern across compile, project, and scan commands
- Merge duplicate GetModelCacheDirPath() calls in prune into single pass
  that scans both models and logs in one loop
- Use sync.Once for LogWriter() init to prevent check-then-assign race
- Skip zero-size model entries in prune scanning (matching log behavior)
- Scope logCachePath inside DryRunScan guard in scan command
Skip printing "Log file" in debug config fields and "Log" in scan
summary when globals.LogPath is empty (e.g. dry-run or no logging).
Reject conflicting flag combinations early:
- source-path argument with --project-model
- --recompile with --project-model
Add build-system marker detection that recursively searches for
Java/Kotlin build files (pom.xml, build.gradle, gradlew, etc.)
up to depth 3, skipping known non-project directories.

- Scan command detects project.yaml and suggests --project-model
- Compile command validates markers without project.yaml check
- Extensible LanguageMarkers registry for future language support
- Cross-platform: includes gradlew.bat and mvnw.cmd for Windows
Return all detected languages instead of stopping at first match.
Uses marker-to-language lookup map for O(1) resolution and preserves
registration order from supportedLanguages.
Previously, passing a non-existent path to scan or compile produced a
misleading "No supported build files found" error. Now both validators
check that the directory exists first, giving a clear error message.
Print the error message first, then the actionable suggestion below it,
so the user sees the problem before the remediation.
@misonijnik misonijnik force-pushed the misonijnik/rework-compile-and-scan branch from a6757ba to f8c1389 Compare April 16, 2026 12:21
Capitalizes the first letter of Go error strings when displaying them to
users. Errors follow Go lowercase convention internally but should read
as sentences in CLI output.
These errors are now capitalized at the display layer by Humanize/ErrorErr,
so the source strings should follow Go convention (lowercase).
…ag factories

Replace hardcoded command strings in suggestions with OpentaintCommandBuilder.
Add currentScanBuilder, currentCompileBuilder, currentSummaryBuilder factories
so adding a new flag requires updating only one place per command. Add
CopyFlagsFrom to propagate flags to Docker builder variants automatically.

- Add NewSummaryCommand, WithShowFindings, WithVerboseFlow, WithShowCodeSnippets
- Add CopyFlagsFrom for creating builder variants that inherit all flags
- Refactor BuildScanCommandWithDocker and BuildCompileCommandWithDocker to
  accept a base builder instead of individual flag parameters
- Render true boolFlags as --flag instead of --flag=true
Fix typo in WithRuleset that prevented default-ruleset skip from firing,
extract shared validation into validateSourceDir, simplify scan logging
activation to use activateLoggingForProject consistently.
@misonijnik misonijnik merged commit bc65934 into main Apr 16, 2026
13 checks passed
@misonijnik misonijnik deleted the misonijnik/rework-compile-and-scan branch April 16, 2026 14:26
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.

1 participant