Skip to content

Commit ff1cff8

Browse files
Resolve the reachability facts file against the target path
Coana runs with its working directory set to --target-path, so a relative --reach-output-file lands there, but the CLI looked for it relative to its own working directory. When the two differed (as in the Docker image), reading the scan ID logged a spurious "Facts file not found" warning, --only-facts-file submitted a file that didn't exist, and --reach-use-only-pregenerated-sboms silently left the facts file out of the upload. Resolve the path once in run_reachability_analysis and use the returned report_path everywhere.
1 parent 506fc21 commit ff1cff8

3 files changed

Lines changed: 32 additions & 9 deletions

File tree

‎socketsecurity/core/tools/reachability.py‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ def run_reachability_analysis(
132132
org_slug: Socket organization slug
133133
target_directory: Directory to analyze
134134
tar_hash: Tar hash from manifest upload or existing scan (optional)
135-
output_path: Output file path for results
135+
output_path: Output file path for results, relative to target_directory unless absolute
136136
timeout: Analysis timeout, forwarded verbatim to coana --analysis-timeout
137137
(coana parses the units, e.g. '90s', '10m', '1h'; a bare number is seconds)
138138
memory_limit: Memory limit, forwarded verbatim to coana --memory-limit
@@ -282,16 +282,17 @@ def run_reachability_analysis(
282282
log.error(f"Reachability analysis failed with exit code {returncode}")
283283
raise Exception(f"Reachability analysis failed with exit code {returncode}")
284284

285-
# Extract scan ID from output file
286-
scan_id = self._extract_scan_id(output_path)
285+
# Coana runs in target_directory, so a relative output_path lands there.
286+
report_path = os.path.join(target_directory, output_path)
287+
scan_id = self._extract_scan_id(report_path)
287288

288289
log.info("Reachability analysis completed successfully")
289290
if scan_id:
290291
log.info(f"Scan ID: {scan_id}")
291292

292293
return {
293294
"scan_id": scan_id,
294-
"report_path": output_path,
295+
"report_path": report_path,
295296
"tar_hash_used": tar_hash
296297
}
297298

‎socketsecurity/socketcli.py‎

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,7 +561,7 @@ def main_code():
561561

562562
# If only-facts-file mode, mark the facts file for submission
563563
if config.only_facts_file:
564-
facts_file_to_submit = os.path.abspath(output_path)
564+
facts_file_to_submit = os.path.abspath(result['report_path'])
565565
log.info(f"Only-facts-file mode: will submit only {facts_file_to_submit}")
566566

567567
# If reach-use-only-pregenerated-sboms mode, submit CDX, SPDX, and facts file
@@ -570,9 +570,8 @@ def main_code():
570570
sbom_files_to_submit = []
571571
for scan_path in scan_paths:
572572
sbom_files_to_submit.extend(core.find_sbom_files(scan_path))
573-
# Use relative path for facts file
574-
if os.path.exists(output_path):
575-
sbom_files_to_submit.append(output_path)
573+
if os.path.exists(result['report_path']):
574+
sbom_files_to_submit.append(result['report_path'])
576575
log.info(f"Pre-generated SBOMs mode: will submit {len(sbom_files_to_submit)} files (CDX, SPDX, and facts file)")
577576

578577
except Exception as e:

‎tests/unit/test_reachability.py‎

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,14 @@
2020

2121
VERSION = "1.2.3"
2222

23-
# Records what it was run with in $FAKE_COANA_RUN, or fails when passed --fail.
23+
# Records what it was run with in $FAKE_COANA_RUN, or fails when passed --fail. Like Coana, it
24+
# writes the facts file to the --socket-mode path, resolved against its cwd.
2425
FAKE_CLI_WRAPPER = """
2526
import { writeFileSync } from 'node:fs'
2627
const args = process.argv.slice(2)
2728
if (args.includes('--fail')) process.exit(1)
2829
writeFileSync(process.env.FAKE_COANA_RUN, JSON.stringify({ args, cwd: process.cwd(), env: process.env }))
30+
writeFileSync(args[args.indexOf('--socket-mode') + 1], JSON.stringify({ tier1ReachabilityScanId: 'reach-scan-id' }))
2931
"""
3032

3133

@@ -84,6 +86,27 @@ def test_runs_the_cached_cli_wrapper_with_the_args_and_cwd(fake_run_path):
8486
assert run["cwd"] == str(fake_run_path.parent)
8587

8688

89+
@pytest.mark.parametrize("absolute", [False, True])
90+
def test_report_path_is_where_coana_wrote_the_facts_file(fake_run_path, tmp_path, monkeypatch, absolute):
91+
target = tmp_path / "project"
92+
target.mkdir()
93+
monkeypatch.chdir(tmp_path)
94+
output_path = str(tmp_path / "out" / "facts.json") if absolute else ".socket.facts.json"
95+
if absolute:
96+
(tmp_path / "out").mkdir()
97+
98+
result = _analyzer().run_reachability_analysis(
99+
org_slug="my-org",
100+
target_directory=str(target),
101+
tar_hash="tar-hash-abc123",
102+
output_path=output_path,
103+
version=VERSION,
104+
)
105+
106+
assert result["report_path"] == (output_path if absolute else str(target / ".socket.facts.json"))
107+
assert result["scan_id"] == "reach-scan-id"
108+
109+
87110
def test_reach_debug_appends_debug_long_flag(fake_run_path):
88111
"""G9: --reach-debug -> coana --debug; does not emit the global -d."""
89112
args = _run(fake_run_path, reach_debug=True)["args"]

0 commit comments

Comments
 (0)