Skip to content

[PPSC-563] feat(auth): remove auth-endpoint flag#98

Merged
yiftach-armis merged 9 commits intomainfrom
feat/PPSC-563-remove-auth-endpoint
Mar 15, 2026
Merged

[PPSC-563] feat(auth): remove auth-endpoint flag#98
yiftach-armis merged 9 commits intomainfrom
feat/PPSC-563-remove-auth-endpoint

Conversation

@yiftach-armis
Copy link
Collaborator

@yiftach-armis yiftach-armis commented Mar 11, 2026

Related Issue

Type of Change

  • New feature (non-breaking change which adds functionality)
  • Documentation update
  • Refactoring (no functional changes)

Problem

The --auth-endpoint flag required users to manually specify the JWT authentication service endpoint, creating unnecessary configuration burden and potential attack surface. Auth credentials now route through moose's unified proxy endpoint automatically.

Solution

  • Replaced AuthEndpoint config with BaseURL derived from --dev flag or production defaults
  • Updated auth client to call /api/v1/auth/token (moose) instead of /api/v1/authenticate (Silk)
  • Removed --auth-endpoint flag and ARMIS_AUTH_ENDPOINT environment variable
  • Added region claim support to JWT for future deployment-aware routing
  • Clarified internal naming (endpointbaseURL in NewAuthClient)
  • Updated documentation and error messages

Testing

  • Unit tests added/updated
  • All tests passing locally
  • Code follows project style guidelines
  • Documentation updated

Reviewer Notes

This change fixes findings from deep-review analysis:

  1. Removed stale documentation references to removed env var
  2. Clarified NewAuthClient naming to match semantic change from endpoint to base URL

Includes region support groundwork for PPSC-543.

Simplify CLI authentication by removing the --auth-endpoint flag entirely.
Auth now routes through moose's proxy endpoint automatically, with the base
URL derived from the --dev flag or hardcoded production endpoint.

Changes:
- Replace AuthEndpoint config with BaseURL (derived from getAPIBaseURL)
- Update auth client endpoint from /api/v1/authenticate to /api/v1/auth/token
- Remove --auth-endpoint flag and ARMIS_AUTH_ENDPOINT environment variable
- Add region claim support to JWT parsing for deployment-aware routing
- Rename endpoint → baseURL in NewAuthClient for semantic clarity
- Update error messages to reflect base URL terminology
- Update all tests and documentation

This simplifies the auth flow by removing a user-configurable endpoint,
reducing attack surface and improving UX when configuring authentication.
Copilot AI review requested due to automatic review settings March 11, 2026 10:10
@github-actions
Copy link

github-actions bot commented Mar 11, 2026

Armis AppSecArmis AppSec Security Scan Results

🟠 HIGH issues found

Severity Count
🟠 HIGH 3
🟡 MEDIUM 2

Total: 5

View all 5 findings

🟠 HIGH (3)

CWE-522_armis-cli_38295677_internal/auth/auth.go_181_2_181_32 - Insecure Design (CWE-522

Location: internal/auth/auth.go:181

Insufficiently Protected Credentials): The GetRawToken method (lines 169‑182) returns the raw JWT token stored in p.credentials.Token directly to the caller without adding any protection such as encryption, masking, or access controls. This behavior matches CWE‑522, which describes exposing sensitive credentials. Because the method is used by the CLI to print the token to stdout when a user explicitly requests it, the credential can be obtained through a user‑facing interface, constituting an immediate external exposure (exposure level ≥6). No sanitization or masking is applied before the token is returned, so the credential is fully disclosed to any code that invokes this function. This makes the vulnerability exploitable by any attacker who can trigger the CLI command or otherwise call GetRawToken, leading to credential leakage.

Code snippet is redacted as it contains secrets.

CWEs: CWE-522: Insufficiently Protected Credentials

CWE-522_armis-cli_38295677_internal/auth/auth.go_171_3_171_28 - Insecure Design (CWE-522

Location: internal/auth/auth.go:171

Insufficiently Protected Credentials): The GetRawToken method returns the stored authentication token directly without any protection or masking. When the provider is operating in legacy mode, it reads the token from p.config.Token, which originates from external configuration (e.g., command‑line flag or environment variable). The method then returns this value to the caller, making the raw credential available to any code that invokes the function. This behavior matches CWE‑522, as it exposes unprotected credentials. The function is reachable from the CLI tool that can print the token to stdout, providing a user‑facing interface that can be leveraged to extract the token. No sanitization or masking is performed, so the credential flow is unimpeded.

Code snippet is redacted as it contains secrets.

CWEs: CWE-522: Insufficiently Protected Credentials

CWE-522_armis-cli_38295677_internal/auth/client.go_52_2_52_33 - Insecure Design (CWE-522

Location: internal/auth/client.go:52

Insufficiently Protected Credentials): The function NewAuthClient permits HTTP URLs when the host is localhost or 127.0.0.1. Later, Authenticate builds a request that includes the clientSecret argument in the JSON body and sends it to the configured authEndpoint. If the client was created with an HTTP localhost URL, the secret is transmitted over an unencrypted HTTP connection, satisfying CWE‑522 (credentials sent without encryption). The secret originates from the clientSecret parameter, flows through JSON marshaling into the request body, and reaches the network sink (http.Client.Do) without any sanitization. Because the request targets an HTTP endpoint, the exposure level is ≥6, making the vulnerability exploitable by an attacker who can observe local network traffic. This constitutes a true positive for insufficiently protected credentials.

Code snippet is redacted as it contains secrets.

CWEs: CWE-522: Insufficiently Protected Credentials

🟡 MEDIUM (2)

CWE-918_armis-cli_38295677_internal/api/client.go_750_2_750_79 - Server-Side Request Forgery (CWE-918

Location: internal/api/client.go:750

Server Side Request Forgery (SSRF)): The function ValidatePresignedURL (lines 719‑755) is intended to block SSRF by ensuring the URL points to an AWS S3 endpoint. It only checks that the host ends with ".amazonaws.com" and contains the substring "s3". An attacker who can supply a URL (the presignedURL argument passed to DownloadFromPresignedURL) can craft a malicious sub‑domain that satisfies both string checks (e.g., evil-s3.attacker.com.amazonaws.com). Because the validation does not verify that the host truly belongs to AWS, the crafted URL passes the check and reaches the sink at line 769 where an HTTP GET request is issued. This creates a reachable SSRF path, matching the described CWE‑918 pattern. The vulnerability resides in the same functionality as line 750, and no effective sanitization is performed, making it exploitable when user‑controlled input reaches the download routine. The code is part of a client library used by internal scripts or CLI tools, giving it a script‑to‑script exposure level (5) and a corresponding low likelihood of exploitation in typical deployments.

CWEs: CWE-918: Server Side Request Forgery (SSRF)

CWE-522_armis-cli_38295677_internal/cmd/auth.go_62_2_62_19 - Insecure Design (CWE-522

Location: internal/cmd/auth.go:62

Insufficiently Protected Credentials): The function runAuth obtains a JWT token via provider.GetRawToken and then prints the raw token directly to standard output with fmt.Println(token). This exposes the authentication credential to any process or script that can read the command's stdout, logs, or command‑line history, which matches the definition of CWE‑522 (Insufficiently Protected Credentials). The token originates from a credential‑derived source and reaches an insecure sink without any sanitization, making the credential reachable. Because the exposure occurs through a CLI output that can be captured by other scripts or logged locally, it is classified as script‑to‑script interaction (exposure level 5), leading to a low likelihood of exploitation in this context.

Code snippet is redacted as it contains secrets.

CWEs: CWE-522: Insufficiently Protected Credentials

@github-actions
Copy link

github-actions bot commented Mar 11, 2026

Test Coverage Report

total: (statements) 80.8%

Coverage by function
github.com/ArmisSecurity/armis-cli/cmd/armis-cli/main.go:19:			main					0.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:61:			copyWithContext				70.4%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:134:			WithHTTPClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:143:			WithUploadHTTPClient			100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:151:			WithAllowLocalURLs			100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:163:			NewClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:211:			IsDebug					100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:225:			setAuthHeader				77.8%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:259:			StartIngest				72.3%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:418:			GetIngestStatus				82.6%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:459:			WaitForIngest				84.6%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:510:			FetchNormalizedResults			74.2%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:565:			FetchAllNormalizedResults		91.7%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:590:			GetScanResult				68.4%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:625:			WaitForScan				90.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:646:			formatBytes				100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:668:			FetchArtifactScanResults		75.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:723:			ValidatePresignedURL			100.0%
github.com/ArmisSecurity/armis-cli/internal/api/client.go:759:			DownloadFromPresignedURL		84.2%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:58:			NewAuthProvider				95.2%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:104:			GetAuthorizationHeader			100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:124:			GetTenantID				85.7%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:141:			GetRegion				85.7%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:156:			IsLegacy				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:169:			GetRawToken				85.7%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:196:			exchangeCredentials			87.9%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:267:			refreshIfNeeded				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/auth.go:297:			parseJWTClaims				93.3%
github.com/ArmisSecurity/armis-cli/internal/auth/client.go:29:			Error					100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/client.go:41:			NewAuthClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/client.go:91:			Authenticate				77.4%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:34:		NewRegionCache				100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:40:		Load					82.4%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:74:		Save					76.9%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:104:		Clear					75.0%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:114:		getFilePath				83.3%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:131:		loadCachedRegion			100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:135:		saveCachedRegion			100.0%
github.com/ArmisSecurity/armis-cli/internal/auth/region_cache.go:139:		clearCachedRegion			100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:60:			InitColors				85.2%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:107:			ColorsEnabled				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:113:			ColorsForced				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:119:			SetOutputToFile				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:125:			GetOutputToFile				0.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:129:			enableColors				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:136:			disableColors				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:151:			parseErrorMessage			92.9%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:182:			PrintError				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:195:			PrintErrorf				0.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:201:			PrintWarning				100.0%
github.com/ArmisSecurity/armis-cli/internal/cli/color.go:206:			PrintWarningf				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/auth.go:33:			init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/auth.go:39:			runAuth					92.9%
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/output_helper.go:27:		Cleanup					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/output_helper.go:53:		ResolveOutput				96.4%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:149:			SetVersion				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:157:			Execute					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:161:			init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:192:			PrintUpdateNotification			81.2%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:234:			printUpdateNotificationOnce		75.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:247:			getEnvOrDefault				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:254:			getEnvOrDefaultInt			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:264:			getAPIBaseURL				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:277:			getAuthProvider				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:289:			getPageLimit				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:296:			validatePageLimit			100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:306:			validateFailOn				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/root.go:324:			getFailOn				100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/scan.go:84:			init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/scan_image.go:152:		init					100.0%
github.com/ArmisSecurity/armis-cli/internal/cmd/scan_repo.go:188:		init					100.0%
github.com/ArmisSecurity/armis-cli/internal/httpclient/client.go:31:		NewClient				100.0%
github.com/ArmisSecurity/armis-cli/internal/httpclient/client.go:57:		Do					86.1%
github.com/ArmisSecurity/armis-cli/internal/output/errno_unix.go:12:		isSyncNotSupported			100.0%
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		91.1%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:580:		truncatePlainLine			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:592:		highlightColumns			93.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:637:		scanDuration				89.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:670:		pluralize				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:679:		renderBriefStatus			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:719:		renderSummaryDashboard			56.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:800:		renderFindings				88.9%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:829:		renderFinding				69.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:919:		renderGroupedFindings			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:943:		groupFindings				96.8%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1000:		severityRank				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1007:		isGitRepo				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1014:		getGitBlame				38.1%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1051:		parseGitBlame				95.2%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1087:		maskEmail				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1110:		getTopLevelDomain			75.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1122:		getHumanDisplayTitle			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1136:		wrapTitle				93.9%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1195:		maskFixForDisplay			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1230:		formatFixSection			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1295:		formatProposedSnippet			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1378:		limitHunkContext			64.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1454:		parseDiffHunk				91.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1476:		parseDiffLines				94.6%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1567:		findInlineChanges			73.5%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1638:		computeLCS				92.3%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1690:		buildTokenPositions			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1706:		tokenizeLine				92.9%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1734:		isWordChar				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1741:		formatDiffWithColorsStyled		77.1%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1815:		extractDiffFilename			80.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1837:		formatDiffHunkLine			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1857:		formatDiffContextLine			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1868:		formatDiffRemoveLine			86.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1909:		formatDiffAddLine			86.4%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1951:		applyInlineHighlights			81.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:1993:		truncateDiffLine			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2000:		truncateDiffLineWithFlag		66.7%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2014:		adjustHighlightSpans			83.3%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2036:		groupDiffHunks				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2067:		collectRenderOps			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2110:		renderChangeBlock			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2169:		formatDiffHunkSeparator			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2184:		formatValidationSection			0.0%
github.com/ArmisSecurity/armis-cli/internal/output/human.go:2241:		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:15:			Format					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:24:			FormatWithOptions			66.7%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:32:			formatWithDebug				0.0%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:58:			maskScanResultForOutput			100.0%
github.com/ArmisSecurity/armis-cli/internal/output/json.go:78:			maskFindingSecrets			100.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:24:		Error					0.0%
github.com/ArmisSecurity/armis-cli/internal/output/output.go:44:		GetFormatter				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/output.go:60:		ShouldFail				100.0%
github.com/ArmisSecurity/armis-cli/internal/output/output.go:78:		CheckExit				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/output/writer.go:51:		validateOutputPath			92.3%
github.com/ArmisSecurity/armis-cli/internal/output/writer.go:88:		NewFileOutput				88.2%
github.com/ArmisSecurity/armis-cli/internal/output/writer.go:142:		Writer					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/writer.go:147:		Close					100.0%
github.com/ArmisSecurity/armis-cli/internal/output/writer.go:164:		FormatFromExtension			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:32:		IsCI					100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:60:		isTerminalWriter			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:68:		NewReader				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:83:		NewWriter				50.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:117:		NewSpinner				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:125:		NewSpinnerWithTimeout			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:141:		NewSpinnerWithContext			100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:149:		SetWriter				100.0%
github.com/ArmisSecurity/armis-cli/internal/progress/progress.go:158:		Start					89.8%
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:46:		NewScanner				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:60:		WithPollInterval			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:66:		WithSBOMVEXOptions			0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:73:		WithPullPolicy				0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:79:		ScanImage				0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:110:		ScanTarball				77.1%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:201:		exportImage				0.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:251:		isDockerAvailable			42.9%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:265:		getDockerCommand			75.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:274:		validateDockerCommand			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:282:		imageExistsLocally			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:290:		determinePullBehavior			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:306:		buildScanResult				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:333:		convertNormalizedFindings		85.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:456:		shouldFilterByExploitability		100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:475:		cleanDescription			100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:494:		isEmptyFinding				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/image/image.go:509:		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/gitchanges.go:52:		GitChangedFiles				82.6%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:102:	gitRepoRoot				80.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:126:	changedUncommitted			41.7%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:155:	changedStaged				75.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:168:	validateRef				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:181:	changedSinceRef				75.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:204:	filterToScanPath			94.1%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:239:	runGit					91.7%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:265:	parseLines				100.0%
github.com/ArmisSecurity/armis-cli/internal/scan/repo/gitchanges.go:285:	combineAndDedupe			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:63:		NewChecker				100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:79:		CheckCached				100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:97:		CheckInBackground			100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:117:		check					85.7%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:160:		fetchLatestVersion			89.5%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:193:		getCacheFilePath			66.7%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:208:		readCache				84.6%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:231:		writeCache				76.9%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:254:		IsNewer					100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:277:		parseVersion				100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:300:		FormatNotification			100.0%
github.com/ArmisSecurity/armis-cli/internal/update/update.go:319:		getUpdateCommand			40.0%
github.com/ArmisSecurity/armis-cli/internal/util/cache.go:21:			GetCacheDir				75.0%
github.com/ArmisSecurity/armis-cli/internal/util/cache.go:41:			GetCacheFilePath			80.0%
github.com/ArmisSecurity/armis-cli/internal/util/format.go:7:			FormatCategory				100.0%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:109:			MaskSecretInLine			86.4%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:163:			maskValue				83.3%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:189:			MaskSecretInLines			100.0%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:203:			MaskSecretInMultiLineString		100.0%
github.com/ArmisSecurity/armis-cli/internal/util/mask.go:217:			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)				80.8%

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 updates JWT authentication to use the configured API base URL (Moose) instead of a separate --auth-endpoint, switches the token exchange route to /api/v1/auth/token, and extends JWT parsing to extract an optional region claim.

Changes:

  • Removed the --auth-endpoint / ARMIS_AUTH_ENDPOINT configuration path and wired JWT auth to use the API base URL (getAPIBaseURL() / ARMIS_API_URL override).
  • Updated the auth client to call POST /api/v1/auth/token and adjusted command/docs/tests accordingly.
  • Added region claim parsing + GetRegion() API on the auth provider, with tests for backward compatibility.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
internal/cmd/root.go Removes authEndpoint flag/var and passes API base URL into auth provider config.
internal/cmd/root_test.go Updates root auth-provider tests to reflect removal of authEndpoint.
internal/cmd/auth.go Removes --auth-endpoint requirement for the (hidden) auth command.
internal/cmd/auth_test.go Updates auth command tests to use ARMIS_API_URL and new route.
internal/auth/client.go Renames endpoint→baseURL and switches token exchange to /api/v1/auth/token.
internal/auth/auth.go Renames config field to BaseURL and adds region extraction + accessor.
internal/auth/auth_test.go Updates tests for BaseURL + new endpoint; adds coverage for region parsing/accessor.
docs/FEATURES.md Removes ARMIS_AUTH_ENDPOINT from documented env vars.
CLAUDE.md Updates internal docs to reflect the new token endpoint and removes ARMIS_AUTH_ENDPOINT.
Comments suppressed due to low confidence (1)

CLAUDE.md:90

  • This environment variable list no longer mentions ARMIS_AUTH_ENDPOINT, but it also doesn't mention ARMIS_API_URL, which the CLI uses as an override for the Moose/API base URL (and is now also used for JWT token exchange). Please add ARMIS_API_URL here so internal docs match the current configuration knobs.
### Environment Variables

- `ARMIS_CLIENT_ID` - Client ID for JWT authentication (recommended)
- `ARMIS_CLIENT_SECRET` - Client secret for JWT authentication
- `ARMIS_API_TOKEN` - API token for Basic authentication (fallback)
- `ARMIS_TENANT_ID` - Tenant identifier (required only with Basic auth; JWT extracts it from token)
- `ARMIS_FORMAT` - Default output format
- `ARMIS_PAGE_LIMIT` - Results pagination size
- `ARMIS_THEME` - Terminal background theme: auto, dark, light (default: auto)

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

- Update NewAuthProvider comment to say "base URL" instead of "endpoint"
- Document ARMIS_API_URL in FEATURES.md and CLAUDE.md env var sections
Add region caching to optimize JWT authentication by persisting the
discovered region to disk and reusing it on subsequent CLI invocations.

Key changes:
- Add --region flag for explicit region override (bypasses auto-discovery)
- Implement file-based region cache (~/.cache/armis-cli/region-cache.json)
- Add automatic retry without region hint when cached region auth fails
- Memoize cached region in AuthProvider to avoid repeated disk I/O
- Extract shared cache directory utility (util.GetCacheDir/GetCacheFilePath)
- Add comprehensive tests for region cache (client ID mismatch, corrupt
  JSON, permissions, etc.)

Region selection priority:
1. --region flag - explicit override
2. Cached region - from previous successful auth
3. Auto-discovery - server tries regions until one succeeds

Addresses review findings:
- F1: No tests for region cache → 249 lines of tests added
- F2: No retry on stale cache → Retry logic with usingCachedHint flag
- F3: Redundant writes → Skip if region unchanged
- F4: Repeated disk I/O → Memoization via cachedRegion/regionLoaded
- F5: Duplicated cache constant → Extracted to util.CacheDirName
Copilot AI review requested due to automatic review settings March 12, 2026 08:38
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

Copilot reviewed 14 out of 14 changed files in this pull request and generated 6 comments.


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

- Skip file permissions test on Windows (Unix permissions not supported)
- Use filepath.Join for platform-agnostic path separators in test assertions
Address PR review comments from Copilot:

- Reject absolute paths and path separators in cache filename parameter
  to prevent filepath.Join from discarding the cache directory
- Add containment check to ensure result stays within cache directory
- Fix incorrect test assumptions about filepath.Join behavior
- Use temp directory in TestPackageLevelFunctions to avoid modifying
  real user cache during tests
- Document ARMIS_REGION environment variable in FEATURES.md and CLAUDE.md
Copilot AI review requested due to automatic review settings March 12, 2026 09:17
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

Copilot reviewed 14 out of 14 changed files in this pull request and generated 4 comments.


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

Address follow-up PR review comments:

- Reject empty, whitespace-only, ".", and ".." filenames in GetCacheFilePath
  to prevent returning directory path instead of file path
- Replace strings.HasPrefix with filepath.Rel for robust path containment
  check (handles case-insensitivity and path separator edge cases)
- Add TestAuthProvider_CachedRegionRetryOnFailure to cover region-caching
  retry logic when auth fails with stale cached region
- Fix CLAUDE.md: ARMIS_REGION is for region-aware authentication,
  not API URL selection
The CLI was sending raw JWT tokens without the "Bearer" prefix,
but the backend middleware expects "Authorization: Bearer <token>"
per RFC 6750. This caused 401 errors when using JWT authentication.

Changes:
- auth.go: Return "Bearer " + token for JWT auth
- client.go: Update comments to match actual behavior
- auth_test.go: Update tests to expect Bearer prefix
Copilot AI review requested due to automatic review settings March 12, 2026 18:51
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

Copilot reviewed 15 out of 15 changed files in this pull request and generated 4 comments.


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

- Fix test containment assertion to use filepath.Rel instead of
  strings.HasPrefix for robust path-boundary checking
- Bound RegionCache.Load file reads with 4KB size limit to prevent
  memory exhaustion from corrupted cache files
- Add typed AuthError with HTTP status code to enable selective retry:
  only retry on region-specific rejections (not 401/transport errors)
- Add deprecation warning when ARMIS_AUTH_ENDPOINT env var is set,
  directing users to ARMIS_API_URL or --region
- Update CI docs to recommend JWT auth credentials
@yiftach-armis yiftach-armis merged commit 2f5ab89 into main Mar 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