Skip to content

Commit 4a587af

Browse files
committed
fix: validate AWS credential settings scope
1 parent c7806d9 commit 4a587af

14 files changed

Lines changed: 143 additions & 7 deletions

File tree

crates/agnix-cli/locales/en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,8 @@ rules:
13001300
sigv4_suggestion: Set streaming, presigned, and sigv4a policies to deny or passthrough, or remove unsupported fields.
13011301
tls_terminate_required: AWS credential re-signing via sandbox.credentials.%{feature} requires sandbox.network.tlsTerminate to be an object
13021302
tls_terminate_suggestion: 'Set sandbox.network.tlsTerminate to an object such as {}, or remove the AWS credential re-signing settings.'
1303+
aws_scope: AWS credential re-signing via sandbox.credentials.%{feature} is ignored in project-level .claude settings
1304+
aws_scope_suggestion: Move the AWS credential re-signing settings to ~/.claude/settings.json, a --settings file, or managed settings.
13031305
cc_set_013:
13041306
message: autoMode.classifyAllShell must be a boolean when present (got %{actual}); Claude Code 2.1.193+ documents this
13051307
auto-mode setting as a strict true/false toggle

crates/agnix-cli/locales/es.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@ rules:
810810
sigv4_suggestion: Establece las politicas streaming, presigned y sigv4a en deny o passthrough, o elimina campos no admitidos.
811811
tls_terminate_required: La firma de credenciales de AWS mediante sandbox.credentials.%{feature} requiere que sandbox.network.tlsTerminate sea un objeto
812812
tls_terminate_suggestion: 'Establece sandbox.network.tlsTerminate en un objeto como {}, o elimina la configuracion de firma de credenciales de AWS.'
813+
aws_scope: La firma de credenciales de AWS mediante sandbox.credentials.%{feature} se ignora en la configuracion .claude a nivel de proyecto
814+
aws_scope_suggestion: Mueve la configuracion de firma de credenciales de AWS a ~/.claude/settings.json, un archivo --settings o la configuracion administrada.
813815
cc_set_013:
814816
message: autoMode.classifyAllShell debe ser un booleano cuando esta presente (se obtuvo %{actual}); Claude Code 2.1.193+
815817
documenta esta configuracion de auto-mode como un interruptor true/false estricto

crates/agnix-cli/locales/zh-CN.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,8 @@ rules:
774774
sigv4_suggestion: 将 streaming、presigned 和 sigv4a 策略设置为 deny 或 passthrough,或移除不支持的字段。
775775
tls_terminate_required: 通过 sandbox.credentials.%{feature} 重新签署 AWS 凭证时,sandbox.network.tlsTerminate 必须是对象
776776
tls_terminate_suggestion: '将 sandbox.network.tlsTerminate 设置为对象(例如 {}),或移除 AWS 凭证重新签署设置。'
777+
aws_scope: 项目级 .claude 设置会忽略通过 sandbox.credentials.%{feature} 进行的 AWS 凭证重新签署
778+
aws_scope_suggestion: 将 AWS 凭证重新签署设置移至 ~/.claude/settings.json、--settings 文件或托管设置。
777779
cc_set_013:
778780
message: autoMode.classifyAllShell 存在时必须是布尔值 (实际为 %{actual}); Claude Code 2.1.193+ 将该 auto-mode 设置记录为严格的 true/false 开关
779781
suggestion: 将 autoMode.classifyAllShell 设置为不带引号的 true 或 false,或移除此字段以保留默认的 auto-mode 分类器范围。

crates/agnix-core/locales/en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,8 @@ rules:
13001300
sigv4_suggestion: Set streaming, presigned, and sigv4a policies to deny or passthrough, or remove unsupported fields.
13011301
tls_terminate_required: AWS credential re-signing via sandbox.credentials.%{feature} requires sandbox.network.tlsTerminate to be an object
13021302
tls_terminate_suggestion: 'Set sandbox.network.tlsTerminate to an object such as {}, or remove the AWS credential re-signing settings.'
1303+
aws_scope: AWS credential re-signing via sandbox.credentials.%{feature} is ignored in project-level .claude settings
1304+
aws_scope_suggestion: Move the AWS credential re-signing settings to ~/.claude/settings.json, a --settings file, or managed settings.
13031305
cc_set_013:
13041306
message: autoMode.classifyAllShell must be a boolean when present (got %{actual}); Claude Code 2.1.193+ documents this
13051307
auto-mode setting as a strict true/false toggle

crates/agnix-core/locales/es.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@ rules:
810810
sigv4_suggestion: Establece las politicas streaming, presigned y sigv4a en deny o passthrough, o elimina campos no admitidos.
811811
tls_terminate_required: La firma de credenciales de AWS mediante sandbox.credentials.%{feature} requiere que sandbox.network.tlsTerminate sea un objeto
812812
tls_terminate_suggestion: 'Establece sandbox.network.tlsTerminate en un objeto como {}, o elimina la configuracion de firma de credenciales de AWS.'
813+
aws_scope: La firma de credenciales de AWS mediante sandbox.credentials.%{feature} se ignora en la configuracion .claude a nivel de proyecto
814+
aws_scope_suggestion: Mueve la configuracion de firma de credenciales de AWS a ~/.claude/settings.json, un archivo --settings o la configuracion administrada.
813815
cc_set_013:
814816
message: autoMode.classifyAllShell debe ser un booleano cuando esta presente (se obtuvo %{actual}); Claude Code 2.1.193+
815817
documenta esta configuracion de auto-mode como un interruptor true/false estricto

crates/agnix-core/locales/zh-CN.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,8 @@ rules:
774774
sigv4_suggestion: 将 streaming、presigned 和 sigv4a 策略设置为 deny 或 passthrough,或移除不支持的字段。
775775
tls_terminate_required: 通过 sandbox.credentials.%{feature} 重新签署 AWS 凭证时,sandbox.network.tlsTerminate 必须是对象
776776
tls_terminate_suggestion: '将 sandbox.network.tlsTerminate 设置为对象(例如 {}),或移除 AWS 凭证重新签署设置。'
777+
aws_scope: 项目级 .claude 设置会忽略通过 sandbox.credentials.%{feature} 进行的 AWS 凭证重新签署
778+
aws_scope_suggestion: 将 AWS 凭证重新签署设置移至 ~/.claude/settings.json、--settings 文件或托管设置。
777779
cc_set_013:
778780
message: autoMode.classifyAllShell 存在时必须是布尔值 (实际为 %{actual}); Claude Code 2.1.193+ 将该 auto-mode 设置记录为严格的 true/false 开关
779781
suggestion: 将 autoMode.classifyAllShell 设置为不带引号的 true 或 false,或移除此字段以保留默认的 auto-mode 分类器范围。

crates/agnix-core/src/rules/claude_settings.rs

Lines changed: 116 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -948,6 +948,7 @@ fn validate_sandbox_credentials(
948948
credentials_obj,
949949
diagnostics,
950950
);
951+
validate_sandbox_credential_aws_scope(path, content, credentials_obj, diagnostics);
951952
}
952953

953954
#[derive(Clone, Copy)]
@@ -1760,6 +1761,66 @@ fn validate_sandbox_credential_aws_tls_termination(
17601761
);
17611762
}
17621763

1764+
fn validate_sandbox_credential_aws_scope(
1765+
path: &Path,
1766+
content: &str,
1767+
credentials: &serde_json::Map<String, serde_json::Value>,
1768+
diagnostics: &mut Vec<Diagnostic>,
1769+
) {
1770+
let feature = match (
1771+
credentials.contains_key("awsPairs"),
1772+
credentials.contains_key("sigv4"),
1773+
) {
1774+
(true, true) => "awsPairs and sigv4",
1775+
(true, false) => "awsPairs",
1776+
(false, true) => "sigv4",
1777+
(false, false) => return,
1778+
};
1779+
1780+
let is_managed = path
1781+
.file_name()
1782+
.and_then(|name| name.to_str())
1783+
.is_some_and(|name| name == "managed-settings.json");
1784+
if is_managed || is_user_settings_path(path) {
1785+
return;
1786+
}
1787+
1788+
let line = find_key_line(content, "awsPairs")
1789+
.or_else(|| find_key_line(content, "sigv4"))
1790+
.or_else(|| find_key_line(content, "credentials"))
1791+
.unwrap_or(1);
1792+
diagnostics.push(
1793+
Diagnostic::warning(
1794+
path.to_path_buf(),
1795+
line,
1796+
0,
1797+
"CC-SET-012",
1798+
t!("rules.cc_set_012.aws_scope", feature = feature),
1799+
)
1800+
.with_suggestion(t!("rules.cc_set_012.aws_scope_suggestion")),
1801+
);
1802+
}
1803+
1804+
fn is_user_settings_path(path: &Path) -> bool {
1805+
if path.file_name().and_then(|name| name.to_str()) != Some("settings.json") {
1806+
return false;
1807+
}
1808+
1809+
let Some(home) = std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE")) else {
1810+
return false;
1811+
};
1812+
let absolute_path = if path.is_absolute() {
1813+
path.to_path_buf()
1814+
} else {
1815+
let Ok(current_dir) = std::env::current_dir() else {
1816+
return false;
1817+
};
1818+
current_dir.join(path)
1819+
};
1820+
1821+
absolute_path == Path::new(&home).join(".claude").join("settings.json")
1822+
}
1823+
17631824
fn has_javascript_capturing_group(pattern: &str) -> bool {
17641825
let bytes = pattern.as_bytes();
17651826
let mut escaped = false;
@@ -3805,7 +3866,11 @@ mod tests {
38053866
}
38063867
}
38073868
}"#;
3808-
assert!(validate(content).iter().all(|d| d.rule != "CC-SET-012"));
3869+
assert!(
3870+
validate_at(".claude/managed-settings.json", content)
3871+
.iter()
3872+
.all(|d| d.rule != "CC-SET-012")
3873+
);
38093874
}
38103875

38113876
#[test]
@@ -3840,7 +3905,7 @@ mod tests {
38403905
}
38413906
}
38423907
}"#;
3843-
let hits: Vec<_> = validate(content)
3908+
let hits: Vec<_> = validate_at(".claude/managed-settings.json", content)
38443909
.into_iter()
38453910
.filter(|diagnostic| diagnostic.rule == "CC-SET-012")
38463911
.collect();
@@ -3860,7 +3925,8 @@ mod tests {
38603925

38613926
#[test]
38623927
fn test_sandbox_credentials_aws_pairs_and_sigv4_containers_are_checked() {
3863-
let diagnostics = validate(
3928+
let diagnostics = validate_at(
3929+
".claude/managed-settings.json",
38643930
r#"{"sandbox":{"network":{"tlsTerminate":{}},"credentials":{"awsPairs":true,"sigv4":[]}}}"#,
38653931
);
38663932
let hits: Vec<_> = diagnostics
@@ -3878,7 +3944,7 @@ mod tests {
38783944
r#"{"sandbox":{"credentials":{"awsPairs":[],"sigv4":{}}}}"#,
38793945
r#"{"sandbox":{"network":{"tlsTerminate":true},"credentials":{"awsPairs":[]}}}"#,
38803946
] {
3881-
let hits: Vec<_> = validate(content)
3947+
let hits: Vec<_> = validate_at(".claude/managed-settings.json", content)
38823948
.into_iter()
38833949
.filter(|diagnostic| diagnostic.rule == "CC-SET-012")
38843950
.collect();
@@ -3887,6 +3953,52 @@ mod tests {
38873953
}
38883954
}
38893955

3956+
#[test]
3957+
fn test_sandbox_credentials_aws_resigning_flags_project_scopes() {
3958+
let content = r#"{
3959+
"sandbox": {
3960+
"network": {"tlsTerminate": {}},
3961+
"credentials": {"awsPairs": [], "sigv4": {}}
3962+
}
3963+
}"#;
3964+
for path in [".claude/settings.json", ".claude/settings.local.json"] {
3965+
let hits: Vec<_> = validate_at(path, content)
3966+
.into_iter()
3967+
.filter(|diagnostic| diagnostic.rule == "CC-SET-012")
3968+
.collect();
3969+
assert_eq!(hits.len(), 1, "expected one scope diagnostic for {path}");
3970+
assert!(hits[0].message.contains("project-level"));
3971+
}
3972+
}
3973+
3974+
#[test]
3975+
fn test_sandbox_credentials_aws_resigning_allows_honored_scopes() {
3976+
let content = r#"{
3977+
"sandbox": {
3978+
"network": {"tlsTerminate": {}},
3979+
"credentials": {"awsPairs": [], "sigv4": {}}
3980+
}
3981+
}"#;
3982+
assert!(
3983+
validate_at(".claude/managed-settings.json", content)
3984+
.iter()
3985+
.all(|diagnostic| diagnostic.rule != "CC-SET-012")
3986+
);
3987+
3988+
let Some(home) = std::env::var_os("HOME").or_else(|| std::env::var_os("USERPROFILE"))
3989+
else {
3990+
return;
3991+
};
3992+
let user_settings = PathBuf::from(home).join(".claude").join("settings.json");
3993+
let diagnostics =
3994+
ClaudeSettingsValidator.validate(&user_settings, content, &LintConfig::default());
3995+
assert!(
3996+
diagnostics
3997+
.iter()
3998+
.all(|diagnostic| diagnostic.rule != "CC-SET-012")
3999+
);
4000+
}
4001+
38904002
#[test]
38914003
fn test_sandbox_credentials_optional_field_types_are_checked() {
38924004
let diagnostics = validate(

crates/agnix-lsp/locales/en.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1300,6 +1300,8 @@ rules:
13001300
sigv4_suggestion: Set streaming, presigned, and sigv4a policies to deny or passthrough, or remove unsupported fields.
13011301
tls_terminate_required: AWS credential re-signing via sandbox.credentials.%{feature} requires sandbox.network.tlsTerminate to be an object
13021302
tls_terminate_suggestion: 'Set sandbox.network.tlsTerminate to an object such as {}, or remove the AWS credential re-signing settings.'
1303+
aws_scope: AWS credential re-signing via sandbox.credentials.%{feature} is ignored in project-level .claude settings
1304+
aws_scope_suggestion: Move the AWS credential re-signing settings to ~/.claude/settings.json, a --settings file, or managed settings.
13031305
cc_set_013:
13041306
message: autoMode.classifyAllShell must be a boolean when present (got %{actual}); Claude Code 2.1.193+ documents this
13051307
auto-mode setting as a strict true/false toggle

crates/agnix-lsp/locales/es.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,8 @@ rules:
810810
sigv4_suggestion: Establece las politicas streaming, presigned y sigv4a en deny o passthrough, o elimina campos no admitidos.
811811
tls_terminate_required: La firma de credenciales de AWS mediante sandbox.credentials.%{feature} requiere que sandbox.network.tlsTerminate sea un objeto
812812
tls_terminate_suggestion: 'Establece sandbox.network.tlsTerminate en un objeto como {}, o elimina la configuracion de firma de credenciales de AWS.'
813+
aws_scope: La firma de credenciales de AWS mediante sandbox.credentials.%{feature} se ignora en la configuracion .claude a nivel de proyecto
814+
aws_scope_suggestion: Mueve la configuracion de firma de credenciales de AWS a ~/.claude/settings.json, un archivo --settings o la configuracion administrada.
813815
cc_set_013:
814816
message: autoMode.classifyAllShell debe ser un booleano cuando esta presente (se obtuvo %{actual}); Claude Code 2.1.193+
815817
documenta esta configuracion de auto-mode como un interruptor true/false estricto

crates/agnix-lsp/locales/zh-CN.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -774,6 +774,8 @@ rules:
774774
sigv4_suggestion: 将 streaming、presigned 和 sigv4a 策略设置为 deny 或 passthrough,或移除不支持的字段。
775775
tls_terminate_required: 通过 sandbox.credentials.%{feature} 重新签署 AWS 凭证时,sandbox.network.tlsTerminate 必须是对象
776776
tls_terminate_suggestion: '将 sandbox.network.tlsTerminate 设置为对象(例如 {}),或移除 AWS 凭证重新签署设置。'
777+
aws_scope: 项目级 .claude 设置会忽略通过 sandbox.credentials.%{feature} 进行的 AWS 凭证重新签署
778+
aws_scope_suggestion: 将 AWS 凭证重新签署设置移至 ~/.claude/settings.json、--settings 文件或托管设置。
777779
cc_set_013:
778780
message: autoMode.classifyAllShell 存在时必须是布尔值 (实际为 %{actual}); Claude Code 2.1.193+ 将该 auto-mode 设置记录为严格的 true/false 开关
779781
suggestion: 将 autoMode.classifyAllShell 设置为不带引号的 true 或 false,或移除此字段以保留默认的 auto-mode 分类器范围。

0 commit comments

Comments
 (0)