Scan layers
A deep scan runs six analysis layers in sequence. Each layer operates on the repository file tree, produces a list of findings, and respects a per-layer budget of 45 seconds (270 seconds total). This page describes what each layer analyses and how it works.
Shallow vs deep scan coverage
Shallow scans run five lightweight checks directly against the GitHub API (no clone). Deep scans clone the repository and run all eleven categories across six dedicated layers.
| Category | Shallow | Deep | Layer |
|---|---|---|---|
| governance | Yes | Yes | Shallow check |
| dependency (basic) | Yes | Yes | Shallow check |
| code_quality (basic) | Yes | Yes | Shallow check |
| security (basic) | Yes | Yes | Shallow check |
| iac (basic) | Yes | Yes | Shallow check |
| dependency (CVE lookup) | No | Yes | DependencyAnalyzer |
| secret | No | Yes | SecretDetector |
| sast | No | Yes | SASTEngine |
| iac (full rules) | No | Yes | IaCScanner |
| license | No | Yes | LicenseAuditor |
| quality | No | Yes | QualityAnalyzer |
Layer execution order and timeouts
Deep layers run sequentially in this order:
- DependencyAnalyzer
- SecretDetector
- SASTEngine
- IaCScanner
- LicenseAuditor
- QualityAnalyzer
Each layer has a 45-second individual timeout. The total deep scan budget is 270 seconds. If a layer times out or raises an unhandled exception, it is skipped and the scan continues with the remaining layers. Partial results are always returned.
Layer 1: DependencyAnalyzer
Parses dependency manifests and queries the GitHub Advisory Database (GHSA) GraphQL API for known CVEs. Also flags unpinned dependency versions.
Supported manifest files
requirements.txtpackage.jsonpackage-lock.jsonPipfileandPipfile.lockpyproject.toml(PEP 621[project].dependencies)go.modandgo.sumGemfileandGemfile.lock
GHSA query batching
Pinned dependencies are queried in batches of 20 against the GHSA GraphQL API. CVE severity is mapped from GHSA's severity classification to ticketyboo severity levels (critical, high, medium, low).
Unpinned versions
A dependency is considered unpinned if its version specifier uses a range operator (>=, ^, ~, *) rather than an exact version. Unpinned dependencies are reported at severity medium.
Layer 2: SecretDetector
Scans source and configuration files for hardcoded credentials using two methods: regex pattern matching and Shannon entropy analysis.
Regex patterns
The layer matches against patterns for:
- AWS access keys and secret keys
- RSA, EC, and SSH private keys
- Database connection URLs containing credentials
- Generic API keys and tokens
- JWT tokens
- Webhook secrets
Shannon entropy
Strings that pass through regex filters are also checked for Shannon entropy. A string with entropy above 4.5 and length of at least 16 characters is flagged as a potential secret at severity high. This catches secrets that do not match known patterns (for example, randomly generated API keys).
Redaction
Detected secret values are redacted before storage. The finding records the pattern type, file path, and line number, but not the secret value itself.
Layer 3: SASTEngine
Static application security testing. Uses Python AST analysis for Python files and regex patterns for JavaScript, Go, and Ruby.
Python AST checks
| Check | What it detects | Severity |
|---|---|---|
| Command injection | subprocess, os.system calls with unsanitised input | critical |
| SQL injection | String concatenation in SQL queries | critical |
| Insecure deserialization | pickle.loads, yaml.load without SafeLoader | high |
| Cross-site scripting | Unescaped user input in HTML rendering | high |
| Path traversal | User-controlled file path operations | high |
| Weak cryptography | MD5, SHA1 usage via hashlib | medium |
File size limit
Files larger than 500 KB are skipped by the SAST layer. A finding is recorded at severity info noting that the file was too large to analyse.
Layer 4: IaCScanner
Analyses Terraform (HCL2) and CloudFormation (YAML/JSON) files for infrastructure security misconfigurations.
Terraform rules
| Check | Resource type | Severity |
|---|---|---|
| S3 bucket without server-side encryption | aws_s3_bucket | high |
| S3 bucket with public ACL | aws_s3_bucket_acl | critical |
| Security group with unrestricted ingress (0.0.0.0/0) | aws_security_group | high |
IAM policy with wildcard action (*) | aws_iam_policy | high |
| RDS instance with encryption disabled | aws_db_instance | high |
CloudFormation rules
| Check | Resource type | Severity |
|---|---|---|
| S3 bucket missing PublicAccessBlock | AWS::S3::Bucket | high |
| Security group with unrestricted ingress | AWS::EC2::SecurityGroup | high |
CloudFormation templates are identified by the presence of an AWSTemplateFormatVersion or Resources key. Terraform files are identified by the .tf extension. HCL2 parsing uses the python-hcl2 library.
Layer 5: LicenseAuditor
Detects license files, classifies them using SPDX identifiers, and flags compatibility issues.
License classification
License files (LICENSE, LICENSE.md, LICENSE.txt, COPYING) are read and matched against SPDX patterns. Classified licenses are reported at severity info. The following classifications trigger higher severity:
| License type | Severity | Reason |
|---|---|---|
| GPL v2, GPL v3, AGPL v3 | high | Strong copyleft; may require source disclosure |
| LGPL v2.1, LGPL v3 | medium | Weak copyleft; linking restrictions |
| No license file detected | medium | All rights reserved by default |
| License field mismatch (package.json vs LICENSE file) | medium | Inconsistent declared license |
Layer 6: QualityAnalyzer
Measures code quality metrics for Python files using AST analysis. Also scans all text files for TODO and FIXME comments.
Python metrics
| Metric | Threshold | Severity |
|---|---|---|
| Cyclomatic complexity per function | > 15 branches | medium |
| Function length | > 100 lines | low |
| File length | > 500 lines | low |
| Type hint coverage | < 50% of function parameters/returns | low |
| TODO/FIXME count | > 5 per repository | low |
Cyclomatic complexity counts decision points (if, elif, for, while, except, with, and, or, assert) per function. A score of 15 indicates a function with high branching complexity that is typically harder to test and maintain.
Finding deduplication
After all layers complete, findings with identical (file_path, category, title) tuples are deduplicated to one finding. This prevents a finding reported by both a shallow check and a deep layer from being counted twice against a gate threshold.