Skip to content

Commit da0b062

Browse files
authored
Merge pull request #1 from Ceaseless04/feat/tests-and-detectors
Additional tests and Detectors
2 parents ffd8373 + 466e7ff commit da0b062

File tree

3 files changed

+56
-1
lines changed

3 files changed

+56
-1
lines changed

README.md

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,25 @@ python -m pytest -q
4646
You should see five tests covering core functionality.
4747

4848

49+
## Project Structure
50+
51+
### Extending detection
52+
53+
The :class:`agentshield.secret_scanner.SecretScanner` class ships with a
54+
set of common regexes (API keys, tokens, AWS formats, JWTs, etc.). If
55+
you need to recognise additional secrets, simply:
56+
57+
```python
58+
from agentshield.secret_scanner import SecretScanner
59+
import re
60+
61+
scanner = SecretScanner()
62+
scanner.register_pattern("MY_SECRET", re.compile(r"mysecret=\S+"))
63+
```
64+
65+
Patterns are applied in the order they are registered, and you can also
66+
provide a custom list during initialization.
67+
4968
## Project Structure
5069

5170
```
@@ -67,4 +86,3 @@ LICENSE
6786
## License
6887

6988
This project is open source under the Apache license.
70-
🛡️ AgentShield is a zero-trust security layer that lets AI agents safely access repositories, tools, and APIs without exposing secrets or proprietary data.

agentshield/secret_scanner.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,31 @@ class SecretScanner:
3434
("ENV_VAR", re.compile(r"\b[A-Z0-9_]+=[^\n]+")),
3535
("TOKEN", re.compile(r"(?i)token\s*=\s*\S+")),
3636
("PASSWORD", re.compile(r"(?i)password\s*=\s*[^\s]+")),
37+
# common provider keys
38+
("AWS_ACCESS_KEY", re.compile(r"AKIA[0-9A-Z]{16}")),
39+
("AWS_SECRET_KEY", re.compile(r"(?i)aws_secret_access_key\s*=\s*\S+")),
40+
("JWT", re.compile(r"[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+\.[A-Za-z0-9-_]+")),
3741
]
3842
# entropy threshold for high-entropy strings
3943
ENTROPY_THRESHOLD: float = 4.5
4044

4145
def __init__(self, patterns: List[tuple[str, Pattern]] | None = None) -> None:
46+
"""Initialize scanner with optional custom patterns list.
47+
48+
``patterns`` should be a list of ``(name, regex)`` tuples. If not
49+
provided, the built-in defaults are used. Callers may also call
50+
:func:`register_pattern` on the instance to add detectors lazily.
51+
"""
4252
self.patterns = patterns or list(self.DEFAULT_PATTERNS)
4353

54+
def register_pattern(self, name: str, pattern: Pattern) -> None:
55+
"""Add a new named regex pattern to this scanner instance.
56+
57+
Useful for plugins or application-specific secrets. Patterns are
58+
evaluated in insertion order during ``scan``.
59+
"""
60+
self.patterns.append((name, pattern))
61+
4462
def scan(self, text: str) -> List[SecretMatch]:
4563
"""Return a list of secrets found in ``text``.
4664

tests/test_scanner.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import re
2+
13
import pytest
24

35
from agentshield.secret_scanner import SecretScanner
@@ -15,3 +17,20 @@ def test_entropy_detector():
1517
scanner = SecretScanner()
1618
results = scanner.scan(high)
1719
assert any(r.secret_type == "HIGH_ENTROPY" for r in results)
20+
21+
22+
def test_additional_patterns():
23+
scanner = SecretScanner()
24+
# AWS access key format (16 characters after prefix)
25+
assert any(r.secret_type == "AWS_ACCESS_KEY" for r in scanner.scan("AKIA1234567890ABCDEF"))
26+
# JWT-like string
27+
jwt = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.TJVA95OrM7E2cBab30RMHrHDcEfhlp"
28+
assert any(r.secret_type == "JWT" for r in scanner.scan(jwt))
29+
30+
31+
def test_register_pattern():
32+
scanner = SecretScanner()
33+
scanner.register_pattern("FOO", re.compile(r"foo=\d+"))
34+
results = scanner.scan("foo=1234")
35+
assert any(r.secret_type == "FOO" for r in results)
36+
assert any(r.secret_type == "FOO" for r in results)

0 commit comments

Comments
 (0)