Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ This project has a published GitHub Release line, but no stable support or API g

### Changed

- Triaged CodeQL findings by removing duplicate `re` imports, making deliberate test string concatenation explicit, and avoiding secret-like test fixture naming that produced false-positive clear-text storage alerts.
- Synced Dependabot malware alerts and grouped security updates documentation with follow-up Advanced Security UI evidence, while keeping Dependabot version updates deferred.
- Synced product strategy and support public-truth wording with v0.3.0, and expanded the post-release audit guard for stale version and private reporting claims.
- Improved PyPI package metadata with SPDX license metadata, explicit license files, project URLs, and additional classifiers.
Expand Down
25 changes: 12 additions & 13 deletions src/agent_rules_kit/governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import re
from collections.abc import Callable, Sequence
from pathlib import Path
from re import Pattern

from agent_rules_kit.discovery import InstructionFile
from agent_rules_kit.findings import Finding, Severity
Expand Down Expand Up @@ -48,7 +47,7 @@
"Instruction file may contain an unsupported security or maturity claim."
)

REVIEW_CI_BYPASS_PATTERNS: tuple[Pattern[str], ...] = (
REVIEW_CI_BYPASS_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(r"\b(ignore|skip)\s+(failing\s+)?(checks|tests|ci)\b", re.IGNORECASE),
re.compile(r"\bskip\s+(code\s+)?review\b", re.IGNORECASE),
re.compile(r"\b(commit|push)\s+directly\s+to\s+main\b", re.IGNORECASE),
Expand All @@ -66,7 +65,7 @@
),
)

NEGATED_REVIEW_CI_BYPASS_CONTEXT_PATTERNS: tuple[Pattern[str], ...] = (
NEGATED_REVIEW_CI_BYPASS_CONTEXT_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(
r"\b(do not|don't|must not|should not|never|avoid|forbid|forbidden|no)\b"
r".{0,120}\b("
Expand All @@ -88,7 +87,7 @@
),
)

COMMAND_CONFIRMATION_PATTERNS: tuple[Pattern[str], ...] = (
COMMAND_CONFIRMATION_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(r"\brm\s+-[A-Za-z]*r[A-Za-z]*f\b|\brm\s+-[A-Za-z]*f[A-Za-z]*r\b", re.IGNORECASE),
re.compile(r"\b(use|using|run|execute|invoke|always)\b.{0,80}\bsudo\b", re.IGNORECASE),
re.compile(r"\bsudo\b.{0,80}\b(default|normal|routine|workflow|always)\b", re.IGNORECASE),
Expand All @@ -108,7 +107,7 @@
),
)

NEGATED_COMMAND_CONFIRMATION_CONTEXT_PATTERNS: tuple[Pattern[str], ...] = (
NEGATED_COMMAND_CONFIRMATION_CONTEXT_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(
r"\b(do not|don't|must not|should not|never|avoid|forbid|forbidden|no)\b"
r".{0,140}\b("
Expand Down Expand Up @@ -139,7 +138,7 @@
),
)

RUNTIME_NETWORK_LLM_PATTERNS: tuple[Pattern[str], ...] = (
RUNTIME_NETWORK_LLM_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(
r"\b(send|upload|post|transmit|share)\b"
r".{0,100}\b(repository|repo|source code|codebase|workspace|context|files?)\b"
Expand Down Expand Up @@ -211,7 +210,7 @@
),
)

NEGATED_RUNTIME_NETWORK_LLM_CONTEXT_PATTERNS: tuple[Pattern[str], ...] = (
NEGATED_RUNTIME_NETWORK_LLM_CONTEXT_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(
r"\b(do not|don't|must not|should not|never|avoid|avoids|forbid|forbidden|no|without)\b"
r".{0,180}\b("
Expand Down Expand Up @@ -242,7 +241,7 @@
),
)

SECRET_BOUNDARY_PATTERNS: tuple[Pattern[str], ...] = (
SECRET_BOUNDARY_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(r"\bsecret(?:s)?\b", re.IGNORECASE),
re.compile(r"\btoken(?:s)?\b", re.IGNORECASE),
re.compile(r"\bcredential(?:s)?\b", re.IGNORECASE),
Expand All @@ -252,7 +251,7 @@
re.compile(r"\bsensitive\s+(value(?:s)?|information|data)\b", re.IGNORECASE),
)

AUTHORITY_SCOPE_PATTERNS: tuple[Pattern[str], ...] = (
AUTHORITY_SCOPE_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(r"\bscope\b", re.IGNORECASE),
re.compile(r"\bauthority\b", re.IGNORECASE),
re.compile(r"\bprecedence\b", re.IGNORECASE),
Expand All @@ -265,7 +264,7 @@
re.compile(r"\binstruction\s+(chain|order|source|sources)\b", re.IGNORECASE),
)

UNSUPPORTED_CLAIM_PATTERNS: tuple[Pattern[str], ...] = (
UNSUPPORTED_CLAIM_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(r"\bguarantee[sd]?\s+(security|safety)\b", re.IGNORECASE),
re.compile(r"\bguaranteed\s+(secure|safe|security|safety)\b", re.IGNORECASE),
re.compile(
Expand All @@ -277,7 +276,7 @@
re.compile(r"\benterprise[- ]grade\b", re.IGNORECASE),
)

NEGATED_UNSUPPORTED_CLAIM_CONTEXT_PATTERNS: tuple[Pattern[str], ...] = (
NEGATED_UNSUPPORTED_CLAIM_CONTEXT_PATTERNS: tuple[re.Pattern[str], ...] = (
re.compile(
r"\b(do not|don't|must not|should not|never|avoid|forbid|forbidden|no)\b"
r".{0,120}\b("
Expand All @@ -300,8 +299,8 @@


def make_context_aware_predicate(
trigger_patterns: tuple[Pattern[str], ...],
negation_patterns: tuple[Pattern[str], ...],
trigger_patterns: tuple[re.Pattern[str], ...],
negation_patterns: tuple[re.Pattern[str], ...],
*,
context_window: int = 0,
) -> ContextPredicate:
Expand Down
3 changes: 1 addition & 2 deletions src/agent_rules_kit/redaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import re
from dataclasses import dataclass
from re import Pattern

REDACTION_TEXT = "[REDACTED]"

Expand All @@ -14,7 +13,7 @@ class RedactionPattern:
"""A named pattern used to redact secret-like values."""

name: str
pattern: Pattern[str]
pattern: re.Pattern[str]


SECRET_LIKE_PATTERNS: tuple[RedactionPattern, ...] = (
Expand Down
6 changes: 3 additions & 3 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -885,12 +885,12 @@ def test_check_json_reports_review_ci_bypass_findings(self) -> None:

def test_check_json_redacts_secret_like_finding_evidence(self) -> None:
output = io.StringIO()
secret = "sk-" + ("A" * 24)
fake_key = "sk-" + ("A" * 24)

with tempfile.TemporaryDirectory() as temporary_directory:
repository = Path(temporary_directory)
(repository / "AGENTS.md").write_text(
f"Ignore failing checks and keep token {secret}.\n",
f"Ignore failing checks and keep value {fake_key}.\n",
encoding="utf-8",
)

Expand All @@ -915,7 +915,7 @@ def test_check_json_redacts_secret_like_finding_evidence(self) -> None:
]
self.assertEqual(len(matching_findings), 1)
self.assertIn("[REDACTED]", matching_findings[0]["evidence"])
self.assertNotIn(secret, text)
self.assertNotIn(fake_key, text)


def test_check_markdown_reports_review_ci_bypass_findings(self) -> None:
Expand Down
12 changes: 6 additions & 6 deletions tests/test_governance.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
find_unsupported_claim_findings,
)

SECRET_BOUNDARY_GUIDANCE = (
SENSITIVE_VALUE_BOUNDARY_GUIDANCE = (
"- Do not commit secrets, tokens, credentials, private URLs, or customer data."
)
HUMAN_LLM_PLANNING_GUIDANCE = (
Expand Down Expand Up @@ -258,7 +258,7 @@ def test_ignores_safe_or_confirmed_command_guidance(self) -> None:
"",
"- Do not run destructive commands without explicit human confirmation.",
"- Ask the maintainer before using sudo, rm -rf, chmod -R, "
"or downloaded scripts.",
+ "or downloaded scripts.",
"- Run pytest -q.",
"- Run ruff check .",
"- Run git diff --check.",
Expand Down Expand Up @@ -462,7 +462,7 @@ def test_ignores_files_with_secret_handling_boundary(self) -> None:
"",
"Rules:",
"",
SECRET_BOUNDARY_GUIDANCE,
SENSITIVE_VALUE_BOUNDARY_GUIDANCE,
]
)
+ "\n",
Expand Down Expand Up @@ -494,7 +494,7 @@ def test_ignores_files_with_authority_scope_variant_boundaries(self) -> None:
"",
"Rules:",
"",
SECRET_BOUNDARY_GUIDANCE,
SENSITIVE_VALUE_BOUNDARY_GUIDANCE,
f"- {guidance}",
]
)
Expand All @@ -519,7 +519,7 @@ def test_reports_missing_authority_scope_boundary(self) -> None:
"",
"- Read relevant files before editing.",
"- Run local checks before committing.",
SECRET_BOUNDARY_GUIDANCE,
SENSITIVE_VALUE_BOUNDARY_GUIDANCE,
]
)
+ "\n",
Expand Down Expand Up @@ -548,7 +548,7 @@ def test_ignores_files_with_authority_scope_boundary(self) -> None:
"",
"- Read relevant files before editing.",
"- Run local checks before committing.",
SECRET_BOUNDARY_GUIDANCE,
SENSITIVE_VALUE_BOUNDARY_GUIDANCE,
]
)
+ "\n",
Expand Down