Skip to content

[PPSC-420] fix(security): mask secrets and fix user-facing bugs for 1.1.0#72

Merged
yiftach-armis merged 3 commits intomainfrom
fix/PPSC-420-release-bug-fixes
Feb 15, 2026
Merged

[PPSC-420] fix(security): mask secrets and fix user-facing bugs for 1.1.0#72
yiftach-armis merged 3 commits intomainfrom
fix/PPSC-420-release-bug-fixes

Conversation

@yiftach-armis
Copy link
Collaborator

@yiftach-armis yiftach-armis commented Feb 15, 2026

Related Issue

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • Security improvement

Problem

Multiple security vulnerabilities and bugs identified for the 1.1.0 release:

  • Secrets potentially leaking through SARIF output, proposed fixes, and debug output
  • Incorrect scan failure handling (returning success instead of error)
  • API response size limit too restrictive for large scan results
  • Missing input validation for CLI flags and file paths
  • Symlink detection issues affecting repository scanning

Solution

Comprehensive fixes including: (1) defense-in-depth secret masking in SARIF output, proposed fixes, and debug output using new utility functions; (2) proper error handling for failed scans and increased MaxAPIResponseSize from 1MB to 50MB; (3) comprehensive input validation for exit codes, timeouts, and file paths; (4) symlink detection fixes using Lstat in tarGzDirectory and calculateDirSize; (5) JUnit format now respects --fail-on flag; (6) improved text wrapping with multi-byte character width calculation.

Testing

  • Unit tests added/updated for secret masking functions
  • All existing tests passing locally
  • Pre-commit hooks passing

Checklist

  • Code follows project style guidelines
  • Pre-commit hooks pass
  • All tests passing

Critical fixes:
- FAILED scan status now properly returns error instead of success
- Reject --exit-code 0 which defeats --fail-on in CI pipelines
- Increase API response limit from 1MB to 50MB with truncation detection

High priority fixes:
- Redirect Docker pull/save output to stderr to prevent stdout pollution
- Add bounds check for CommitSHA slicing to prevent panic

Medium priority fixes:
- Validate --scan-timeout and --upload-timeout require values >= 1
- Warn when --sbom-output/--vex-output used without --sbom/--vex flags
- JUnit formatter now respects --fail-on severities instead of hardcoding
- Fix symlink detection using os.Lstat instead of os.Stat
- Use runewidth.StringWidth for proper Unicode text wrapping
- Use rune-based slicing for column highlighting with multi-byte chars
- Validate path/tarball existence before making auth network calls
- Warn when both --tarball and image name are provided
Adds defense-in-depth secret masking for fix content in SARIF output and proposed fixes to prevent leaking secrets in code patches. New utility functions mask secrets in multi-line strings and string maps. Adds corresponding unit tests for masking functionality.
Copilot AI review requested due to automatic review settings February 15, 2026 16:23
@github-actions
Copy link

github-actions bot commented Feb 15, 2026

🛡️ Armis Security Scan Results

🟠 HIGH issues found

Severity Count
🟠 HIGH 2

Total: 2

View all 2 findings

🟠 HIGH (2)

CWE-770_armis-cli_internal/api/client.go_444_4_444_60 - Results from each paginated API response are appended to a slice without any ...

Location: internal/api/client.go:444

Results from each paginated API response are appended to a slice without any overall cap, potentially leading to unbounded memory growth if many pages are returned.

CWEs: CWE-770: Allocation of Resources Without Limits or Throttling

CWE-770_armis-cli_internal/api/client.go_239_2_239_52 - The code copies the entire artifact data (opts.Data) into a multipart form pa...

Location: internal/api/client.go:239

The code copies the entire artifact data (opts.Data) into a multipart form part without enforcing a size limit, allowing an attacker to provide a stream that exceeds expected bounds and cause memory exhaustion.

CWEs: CWE-770: Allocation of Resources Without Limits or Throttling

@github-actions
Copy link

github-actions bot commented Feb 15, 2026

Test Coverage Report

total: (statements) 78.7%

Coverage by function
github.com/ArmisSecurity/armis-cli/cmd/armis-cli/main.go:18:			main					0.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:67:			WithHTTPClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:76:			WithAllowLocalURLs			100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:88:			NewClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:138:			IsDebug					100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:155:			setAuthHeader				77.8%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:189:			StartIngest				73.6%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:286:			GetIngestStatus				82.6%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:327:			WaitForIngest				84.6%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:378:			FetchNormalizedResults			74.2%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:433:			FetchAllNormalizedResults		91.7%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:458:			GetScanResult				68.4%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:493:			WaitForScan				90.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:514:			formatBytes				100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:536:			FetchArtifactScanResults		75.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:591:			ValidatePresignedURL			100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:627:			DownloadFromPresignedURL		84.2%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:52:			NewAuthProvider				95.2%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:98:			GetAuthorizationHeader			100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:118:			GetTenantID				85.7%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:133:			IsLegacy				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:146:			GetRawToken				85.7%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:163:			exchangeCredentials			83.3%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:193:			refreshIfNeeded				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:222:			parseJWTClaims				93.3%
github.com/ArmisSecurity/armis-cli/internal/auth/client.go:31:			NewAuthClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/client.go:72:			Authenticate				71.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:54:			InitColors				73.3%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:82:			ColorsEnabled				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:88:			ColorsForced				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:92:			enableColors				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:99:			disableColors				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:114:			parseErrorMessage			92.9%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:145:			PrintError				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:158:			PrintErrorf				0.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:164:			PrintWarning				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:169:			PrintWarningf				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/auth.go:35:			init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/auth.go:39:			runAuth					93.8%
github.com/ArmisSecurity/armis-cli/internal/cmd/context.go:24:			NewSignalContext			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/context.go:33:			handleScanError				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/help.go:30:			SetupHelp				91.7%
github.com/ArmisSecurity/armis-cli/internal/cmd/help.go:58:			styledUsageTemplate			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/help.go:101:			defaultUsageTemplate			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/help.go:108:			initColorsForHelp			35.3%
github.com/ArmisSecurity/armis-cli/internal/cmd/help.go:149:			styleHelpOutput				83.3%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:119:			SetVersion				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:127:			Execute					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:131:			init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:160:			PrintUpdateNotification			0.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:177:			getEnvOrDefault				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:184:			getEnvOrDefaultInt			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:194:			getAPIBaseURL				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:203:			getAuthProvider				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:214:			getPageLimit				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:221:			validatePageLimit			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:231:			validateFailOn				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:249:			getFailOn				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/scan.go:83:			init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/scan_image.go:145:		init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/scan_repo.go:135:		init					100.0%
github.com/ArmisSecurity/armis-cli/internal/httpclient/client.go:30:		NewClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/httpclient/client.go:56:		Do					85.3%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:54:			wrapText				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:77:			wrapLine				91.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:115:		formatRecommendations			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:185:		wrapTextWithFirstLinePrefix		90.9%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:224:		write					66.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:255:		Write					89.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:285:		Format					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:290:		FormatWithOptions			84.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:360:		SyncColors				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:364:		sortFindingsBySeverity			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:375:		loadSnippetFromFile			69.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:487:		formatCodeSnippetWithFrame		0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:569:		truncatePlainLine			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:581:		highlightColumns			93.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:626:		scanDuration				89.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:659:		pluralize				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:668:		renderBriefStatus			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:708:		renderSummaryDashboard			56.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:789:		renderFindings				88.9%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:818:		renderFinding				61.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:898:		renderGroupedFindings			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:922:		groupFindings				96.8%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:979:		severityRank				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:986:		isGitRepo				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:993:		getGitBlame				38.1%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1030:		parseGitBlame				95.2%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1066:		maskEmail				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1089:		getTopLevelDomain			75.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1101:		getHumanDisplayTitle			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1115:		wrapTitle				93.9%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1173:		formatFixSection			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1235:		formatProposedSnippet			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1318:		limitHunkContext			64.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1394:		parseDiffHunk				91.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1416:		parseDiffLines				94.6%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1507:		findInlineChanges			73.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1578:		computeLCS				92.3%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1630:		buildTokenPositions			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1641:		tokenizeLine				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1663:		isWordChar				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1670:		formatDiffWithColorsStyled		77.1%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1744:		extractDiffFilename			80.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1766:		formatDiffHunkLine			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1786:		formatDiffContextLine			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1797:		formatDiffRemoveLine			86.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1838:		formatDiffAddLine			86.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1880:		applyInlineHighlights			81.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1922:		truncateDiffLine			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1929:		truncateDiffLineWithFlag		66.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1943:		adjustHighlightSpans			83.3%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1965:		groupDiffHunks				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1996:		collectRenderOps			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2039:		renderChangeBlock			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2098:		formatDiffHunkSeparator			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2113:		formatValidationSection			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2170:		getExposureDescription			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/icons.go:24:			GetConfidenceIcon			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:14:			Format					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:21:			FormatWithOptions			66.7%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:29:			formatWithDebug				0.0%
github.com/ArmisSecurity/armis-cli/internal/output/junit.go:48:			Format					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/junit.go:55:			FormatWithOptions			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/junit.go:63:			formatWithSeverities			83.3%
github.com/ArmisSecurity/armis-cli/internal/output/junit.go:88:			isFailureSeverity			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/junit.go:98:			convertToJUnitCasesWithSeverities	91.7%
github.com/ArmisSecurity/armis-cli/internal/output/junit.go:130:		countFailuresWithSeverities		100.0%
github.com/ArmisSecurity/armis-cli/internal/output/output.go:34:		GetFormatter				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/output.go:50:		ShouldFail				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/output.go:66:		ExitIfNeeded				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:159:		stripMarkdown				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:170:		Format					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:197:		buildRules				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:261:		convertToSarifResults			88.5%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:351:		buildMessageText			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:358:		severityToSarifLevel			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:377:		severityToSecurityScore			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:395:		generateHelpURI				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:422:		convertFixToSarif			90.5%
github.com/ArmisSecurity/armis-cli/internal/output/sarif.go:539:		FormatWithOptions			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/styles.go:138:		DefaultStyles				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/styles.go:276:		NoColorStyles				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/styles.go:353:		GetStyles				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/styles.go:361:		SyncStylesWithColorMode			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/styles.go:386:		GetSeverityText				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/styles.go:414:		TerminalWidth				33.3%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:21:		GetLexer				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:32:		GetChromaStyle				80.0%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:45:		HighlightCode				81.2%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:79:		HighlightLine				75.0%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:88:		getTerminalFormatter			60.0%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:103:		HighlightLineWithBackground		87.5%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:126:		getBackgroundANSI			58.3%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:158:		rgbToANSI256				0.0%
github.com/ArmisSecurity/armis-cli/internal/output/syntax.go:171:		parseHexColor				76.9%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:33:		IsCI					100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:61:		isTerminalWriter			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:69:		NewReader				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:84:		NewWriter				50.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:118:		NewSpinner				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:126:		NewSpinnerWithTimeout			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:142:		NewSpinnerWithContext			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:150:		SetWriter				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:159:		Start					86.4%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:268:		Stop					100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:303:		Update					100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:310:		GetElapsed				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:317:		formatDuration				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/finding_type.go:9:		DeriveFindingType			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:44:		NewScanner				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:58:		WithPollInterval			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:64:		WithSBOMVEXOptions			0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:70:		ScanImage				0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:103:		ScanTarball				77.1%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:194:		exportImage				0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:235:		isDockerAvailable			42.9%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:249:		getDockerCommand			75.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:258:		validateDockerCommand			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:265:		buildScanResult				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:292:		convertNormalizedFindings		85.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:415:		shouldFilterByExploitability		100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:434:		cleanDescription			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:453:		isEmptyFinding				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:468:		generateFindingTitle			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/validate.go:11:		validateImageName			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/mask.go:21:			MaskFixSecrets				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/files.go:26:		ParseFileList				87.5%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/files.go:41:		addFile					87.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/files.go:93:		Files					100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/files.go:98:		RepoRoot				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/files.go:103:		ValidateExistence			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/ignore.go:18:		LoadIgnorePatterns			75.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/ignore.go:52:		loadIgnoreFile				89.5%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/ignore.go:86:		Match					100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/ignore.go:98:		shouldSkipDir				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:43:		NewScanner				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:57:		WithPollInterval			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:63:		WithIncludeFiles			0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:69:		WithSBOMVEXOptions			0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:75:		Scan					70.9%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:240:		tarGzDirectory				71.8%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:323:		isPathContained				75.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:332:		tarGzFiles				78.6%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:419:		calculateFilesSize			0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:440:		calculateDirSize			81.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:480:		shouldSkip				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:511:		isTestFile				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:555:		buildScanResult				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:582:		convertNormalizedFindings		73.3%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:705:		shouldFilterByExploitability		100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:724:		cleanDescription			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:745:		generateFindingTitle			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/repo.go:749:		isEmptyFinding				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/sbom_vex.go:38:		NewSBOMVEXDownloader			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/sbom_vex.go:50:		Download				85.2%
github.com/ArmisSecurity/armis-cli/internal/scan/sbom_vex.go:102:		downloadAndSave				77.8%
github.com/ArmisSecurity/armis-cli/internal/scan/status.go:16:			FormatScanStatus			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/status.go:35:			FormatElapsed				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/status.go:48:			MapSeverity				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/testhelpers/findings.go:9:	CreateNormalizedFinding			0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/testhelpers/findings.go:14:	CreateNormalizedFindingWithLabels	0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/testhelpers/findings.go:19:	CreateNormalizedFindingFull		0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/title.go:14:			GenerateFindingTitle			0.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:66:		NewChecker				100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:81:		CheckInBackground			100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:101:		check					85.7%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:144:		fetchLatestVersion			89.5%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:177:		getCacheFilePath			44.4%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:195:		readCache				84.6%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:218:		writeCache				76.9%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:241:		IsNewer					100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:264:		parseVersion				100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:287:		FormatNotification			100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:305:		getUpdateCommand			40.0%
github.com/ArmisSecurity/armis-cli/internal/util/format.go:7:			FormatCategory				100.0%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:54:			MaskSecretInLine			81.2%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:93:			maskValue				83.3%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:119:			MaskSecretInLines			100.0%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:133:			MaskSecretInMultiLineString		100.0%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:147:			MaskSecretsInStringMap			100.0%
github.com/ArmisSecurity/armis-cli/internal/util/path.go:13:			SanitizePath				90.9%
github.com/ArmisSecurity/armis-cli/internal/util/path.go:51:			SafeJoinPath				87.5%
github.com/ArmisSecurity/armis-cli/test/sample-repo/src/main.go:6:		main					0.0%
total:										(statements)				78.7%

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the CLI for the 1.1.0 release by preventing secret leakage across outputs/debug paths and addressing multiple correctness/UX issues in scanning, output formatting, and API handling.

Changes:

  • Add defense-in-depth secret masking for multi-line strings, fix proposals, and SARIF/JUnit-related output paths.
  • Improve scan behavior and UX: better symlink handling, safer stdout/stderr separation, and additional CLI input/path validation.
  • Increase allowed API response size and fix scan failure handling to return errors on FAILED states.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
internal/util/mask.go Adds helpers to mask secrets in multi-line strings and string maps.
internal/util/mask_test.go Adds unit tests for the new masking helpers.
internal/scan/mask.go Introduces scan.MaskFixSecrets to sanitize Fix payload code fields.
internal/scan/mask_test.go Adds unit tests to verify fix masking behavior and immutability.
internal/scan/repo/repo.go Attempts to improve symlink skipping and masks fix data in debug + findings.
internal/scan/image/image.go Routes docker/podman output to stderr and masks fix data in debug + findings.
internal/output/sarif.go Masks fix/patch content when emitting SARIF (defense-in-depth).
internal/output/output.go Extends FormatOptions with FailOnSeverities.
internal/output/junit.go Makes JUnit failure logic respect FailOnSeverities (with defaults).
internal/output/junit_test.go Updates tests for new JUnit severity-based failure logic.
internal/output/human.go Improves wrapping/highlighting for multi-byte characters; avoids short-SHA slicing panic.
internal/cmd/scan.go Adds validation for exit code and timeout flags.
internal/cmd/scan_repo.go Validates repo path early; warns on unused SBOM/VEX output flags; passes fail-on severities to formatters.
internal/cmd/scan_image.go Validates tarball path early; warns on unused SBOM/VEX output flags and conflicting inputs; passes fail-on severities to formatters.
internal/api/client.go Increases max API response size; returns error on FAILED ingest; adds “truncated response” detection.
internal/api/client_test.go Updates tests to assert FAILED ingest returns an error even without LastError.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 410 to +418
bodyBytes, err := io.ReadAll(io.LimitReader(resp.Body, MaxAPIResponseSize))
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}

// Detect if response was truncated at the limit
if int64(len(bodyBytes)) >= MaxAPIResponseSize {
return nil, fmt.Errorf("response too large (exceeded %d MB limit); try reducing --page-limit", MaxAPIResponseSize/(1024*1024))
}
Copy link

Copilot AI Feb 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FetchNormalizedResults reads the body with io.LimitReader(..., MaxAPIResponseSize) and then errors when len(bodyBytes) >= MaxAPIResponseSize. This can incorrectly fail when the response size is exactly at the limit (not truncated). Consider reading MaxAPIResponseSize+1 bytes and only erroring when the read exceeds the limit (e.g., len > MaxAPIResponseSize).

Copilot uses AI. Check for mistakes.
filepath.Walk already uses os.Lstat internally, so the info parameter
already contains symlink information. The extra Lstat calls added
unnecessary syscalls that could slow down scanning on large repos.
@yiftach-armis yiftach-armis merged commit 8f04334 into main Feb 15, 2026
9 checks passed
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.

2 participants