Skip to content
Open
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
27 changes: 24 additions & 3 deletions src/agentready/assessors/security.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,11 +187,17 @@ def assess(self, repository: Repository) -> Finding:
pkg = json.loads(package_json.read_text())
scripts = pkg.get("scripts", {})

# Check for npm audit or yarn audit in scripts
if any("audit" in str(v) for v in scripts.values()):
# Check for npm/yarn/bun audit in scripts
audit_scripts = [
str(v) for v in scripts.values() if "audit" in str(v)
]
if audit_scripts:
score += 10
tools_found.append("npm/yarn audit")
evidence.append("✓ npm/yarn audit configured")
if any("bun" in s for s in audit_scripts):
evidence.append("✓ bun audit configured")
else:
evidence.append("✓ npm/yarn audit configured")

# Check for Snyk
deps = {
Expand All @@ -205,6 +211,21 @@ def assess(self, repository: Repository) -> Finding:
except Exception:
pass

# Check for dependency audit step in CI workflows (npm/yarn/bun/pnpm)
workflows_dir = repository.path / ".github" / "workflows"
if workflows_dir.exists():
for wf in list(workflows_dir.glob("*.yml")) + list(
workflows_dir.glob("*.yaml")
):
try:
if re.search(r"\b(?:bun|npm|yarn|pnpm)\s+audit\b", wf.read_text()):
score += 10
tools_found.append("CI dependency audit")
evidence.append("✓ Dependency audit step in CI workflow")
break
except OSError:
continue

# 5. Secret detection in pre-commit (20 points)
precommit_config = repository.path / ".pre-commit-config.yaml"
if precommit_config.exists():
Expand Down
40 changes: 40 additions & 0 deletions tests/unit/test_assessors_security.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,46 @@ def test_javascript_security_tools(self, tmp_path):
or "Snyk" in finding.measured_value
)

def test_bun_audit_in_ci_workflow(self, tmp_path):
"""Test that bun audit in a CI workflow is detected."""
# Initialize git repository
subprocess.run(["git", "init"], cwd=tmp_path, capture_output=True, check=True)

# Create a bare package.json (no audit script) and a workflow with bun audit
package_json = tmp_path / "package.json"
package_json.write_text('{"scripts": {"test": "vitest run"}}\n')

workflows_dir = tmp_path / ".github" / "workflows"
workflows_dir.mkdir(parents=True)
(workflows_dir / "ci.yml").write_text(
"name: CI\n"
"on: [push, pull_request]\n"
"jobs:\n"
" quality:\n"
" runs-on: ubuntu-latest\n"
" steps:\n"
" - uses: oven-sh/setup-bun@v2\n"
" - run: bun install --frozen-lockfile\n"
" - run: bun audit\n"
)

repo = Repository(
path=tmp_path,
name="test-repo",
url=None,
branch="main",
commit_hash="abc123",
languages={"TypeScript": 100},
total_files=10,
total_lines=100,
)

assessor = DependencySecurityAssessor()
finding = assessor.assess(repo)

assert finding.score >= 10
assert any("audit" in e for e in finding.evidence)

def test_renovate_json_configuration(self, tmp_path):
"""Test that Renovate configuration in renovate.json is detected."""
# Initialize git repository
Expand Down