mirror of
https://github.com/SquidSec/SquidGate
synced 2026-08-09 12:22:48 +00:00
release: rebrand as SquidGate and prepare for open source
- Product name SquidGate (check run, action, package, docs) - Config path .github/squidgate.yml - MIT © SquidSec; production README and docs - CONTRIBUTING, SECURITY, CHANGELOG - CI verifies dist/ is current
This commit is contained in:
@@ -1,15 +1,12 @@
|
||||
# .github/security-scan.yml
|
||||
# Default strict security policy for PRs
|
||||
# SquidGate — dogfood config for this repository
|
||||
version: 1
|
||||
|
||||
llm:
|
||||
provider: custom # openai | anthropic | azure | google | custom
|
||||
provider: custom
|
||||
model: grok-build-0.1
|
||||
# For xAI Grok: base url is passed via action input or here if using openai provider with custom endpoint
|
||||
|
||||
|
||||
policy:
|
||||
block_on: high # critical | high | medium | low | none
|
||||
block_on: high
|
||||
min_confidence: medium
|
||||
categories:
|
||||
secrets: true
|
||||
@@ -1,10 +1,10 @@
|
||||
# .github/security-scan.yml
|
||||
# Default strict security policy for PRs
|
||||
# SquidGate config — copy to .github/squidgate.yml
|
||||
# https://github.com/SquidSec/SquidGate
|
||||
version: 1
|
||||
|
||||
llm:
|
||||
provider: openai # openai | anthropic | azure | google | custom
|
||||
model: gpt-4o # or claude-3-5-sonnet-20241022, gemini-1.5-pro, etc.
|
||||
provider: openai # openai | anthropic | azure | google | custom
|
||||
model: gpt-4o # or claude-*, gemini-*, grok-*, etc.
|
||||
|
||||
policy:
|
||||
block_on: high # critical | high | medium | low | none
|
||||
@@ -2,20 +2,30 @@ name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
pull_request:
|
||||
branches: [ main ]
|
||||
branches: [main]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest # Change to [self-hosted, linux] or your runner label as needed
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'npm'
|
||||
|
||||
- run: npm ci
|
||||
- run: npm test
|
||||
- run: npm run build
|
||||
- run: npm run package
|
||||
- name: Ensure dist is up to date
|
||||
run: |
|
||||
git diff --exit-code dist/ || {
|
||||
echo "::error::dist/ is stale. Run npm run build and commit dist/"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
name: Security Scan
|
||||
name: SquidGate
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -10,21 +10,17 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
security-scan:
|
||||
squidgate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Run security-scan
|
||||
uses: ./ # for local testing; in real use: your-org/security-scan@v1
|
||||
- name: SquidGate
|
||||
uses: ./
|
||||
with:
|
||||
llm-api-key: ${{ secrets.LLM_API_KEY }}
|
||||
llm-provider: custom
|
||||
llm-model: grok-build-0.1
|
||||
llm-base-url: https://api.x.ai/v1
|
||||
# github-token: ${{ secrets.GITHUB_TOKEN }} # default is sufficient
|
||||
# block-on: high
|
||||
# To relax for testing: block-on: none
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to **SquidGate** are documented here.
|
||||
|
||||
## [1.0.0] — 2026-07-28
|
||||
|
||||
### Added
|
||||
|
||||
- Initial public release under MIT as **SquidGate**
|
||||
- Diff-first LLM PR security gate (GitHub Action)
|
||||
- Providers: OpenAI, Anthropic, Google, Azure, custom (xAI Grok, Ollama, …)
|
||||
- Strict default policy (OWASP / CWE-oriented)
|
||||
- Configurable `block_on`, confidence filter, custom rules
|
||||
- GitHub Check Run (`SquidGate`) + line annotations + optional PR comment
|
||||
- Unit tests for config, prompts, parsing, checks
|
||||
- Docs: configuration, privacy, development
|
||||
@@ -0,0 +1,35 @@
|
||||
# Contributing to SquidGate
|
||||
|
||||
Thanks for helping. Built by [SquidSec](https://www.SquidOffense.com).
|
||||
|
||||
## Quick path
|
||||
|
||||
1. Fork + branch from `main`
|
||||
2. `npm ci && npm test`
|
||||
3. Make changes; keep modules small and tested
|
||||
4. `npm run build` (updates `dist/`)
|
||||
5. Open a PR — SquidGate will scan it
|
||||
|
||||
## Guidelines
|
||||
|
||||
- **Tests required** for behavior changes
|
||||
- **No secrets** in commits
|
||||
- Match existing TypeScript style
|
||||
- Prefer pure functions in `config` / `prompts` / `llm`
|
||||
- Update docs when schema or inputs change
|
||||
|
||||
## Good first PRs
|
||||
|
||||
- Provider adapters
|
||||
- Better JSON recovery from noisy models
|
||||
- Optional SARIF upload
|
||||
- Annotation / PR comment UX
|
||||
- Docs and monorepo examples
|
||||
|
||||
## Security research
|
||||
|
||||
See [SECURITY.md](SECURITY.md).
|
||||
|
||||
## License
|
||||
|
||||
Contributions are licensed under MIT.
|
||||
@@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2026 security-scan contributors
|
||||
Copyright (c) 2026 SquidSec
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,23 +1,44 @@
|
||||
# security-scan
|
||||
# SquidGate
|
||||
|
||||
LLM-powered GitHub Action that acts as a configurable PR security gate.
|
||||
[](https://github.com/SquidSec/SquidGate/actions/workflows/ci.yml)
|
||||
[](LICENSE)
|
||||
[](action.yml)
|
||||
[](https://nodejs.org/)
|
||||
|
||||
It analyzes the diff of a pull request using an LLM (chosen and paid for by you) and fails the required status check when findings meet or exceed your configured severity threshold.
|
||||
**LLM-powered PR security gate for GitHub**
|
||||
*by [SquidSec](https://www.SquidOffense.com)*
|
||||
|
||||
- Language-agnostic (any text)
|
||||
- Diff-first + configurable context
|
||||
- Strict-by-default, fully tunable
|
||||
- Supports OpenAI, Anthropic, Google, Azure, custom OpenAI-compatible endpoints
|
||||
- Creates annotated GitHub Checks + optional PR comment
|
||||
- Blocks merges via standard "Require status checks"
|
||||
> One workflow. Every pull request analyzed for security issues.
|
||||
> Findings above your threshold fail the check and can block merge.
|
||||
|
||||
## Quick Start
|
||||
Language-agnostic. You choose (and pay for) the model — OpenAI, Anthropic, Google, Azure, **Grok / xAI**, Ollama, or any OpenAI-compatible endpoint.
|
||||
|
||||
1. Add the workflow:
|
||||
---
|
||||
|
||||
## Why SquidGate?
|
||||
|
||||
| | Traditional SAST | SquidGate |
|
||||
|---|---|---|
|
||||
| Languages | Per-language rules | Any text-based source |
|
||||
| Setup | Days of tuning | **~2 minutes** |
|
||||
| Context | Whole-repo noise | **Diff-first** + context window |
|
||||
| Model | Fixed engine | **Your** LLM |
|
||||
| Merge gate | Separate tooling | Native GitHub Check |
|
||||
| Privacy | Vendor by default | **Only** your endpoint |
|
||||
|
||||
Strict by default (OWASP / CWE-oriented). Relax when you mean to.
|
||||
|
||||
---
|
||||
|
||||
## 60-second setup
|
||||
|
||||
### 1. Add the workflow
|
||||
|
||||
Create `.github/workflows/squidgate.yml`:
|
||||
|
||||
```yaml
|
||||
# .github/workflows/security-scan.yml
|
||||
name: Security Scan
|
||||
name: SquidGate
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened]
|
||||
@@ -28,89 +49,181 @@ permissions:
|
||||
checks: write
|
||||
|
||||
jobs:
|
||||
security-scan:
|
||||
squidgate:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- uses: your-org/security-scan@v1
|
||||
|
||||
- name: SquidGate
|
||||
uses: SquidSec/SquidGate@v1
|
||||
with:
|
||||
llm-api-key: ${{ secrets.LLM_API_KEY }}
|
||||
```
|
||||
|
||||
2. Store your LLM key as a repository secret `LLM_API_KEY`.
|
||||
### 2. Add your LLM API key
|
||||
|
||||
3. (Recommended) Enable branch protection: **Require status checks** → select `security-scan`.
|
||||
**Settings → Secrets and variables → Actions → New repository secret**
|
||||
|
||||
## Configuration
|
||||
| Name | Value |
|
||||
|------|--------|
|
||||
| `LLM_API_KEY` | Your provider key |
|
||||
|
||||
Primary configuration lives in `.github/security-scan.yml` (or override via action inputs).
|
||||
### 3. Block merges (recommended)
|
||||
|
||||
See `.github/security-scan.yml.example` for the full reference.
|
||||
**Settings → Branches → Branch protection** on `main`:
|
||||
|
||||
### Minimal config (strict defaults)
|
||||
- Require status checks to pass
|
||||
- Select **`SquidGate`**
|
||||
|
||||
Open a PR. Done.
|
||||
|
||||
---
|
||||
|
||||
## Using Grok (xAI)
|
||||
|
||||
```yaml
|
||||
- uses: SquidSec/SquidGate@v1
|
||||
with:
|
||||
llm-api-key: ${{ secrets.LLM_API_KEY }}
|
||||
llm-provider: custom
|
||||
llm-model: grok-build-0.1
|
||||
llm-base-url: https://api.x.ai/v1
|
||||
```
|
||||
|
||||
Key: [console.x.ai](https://console.x.ai/)
|
||||
|
||||
---
|
||||
|
||||
## Configuration (optional)
|
||||
|
||||
Defaults are production-ready. Override with `.github/squidgate.yml`:
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
|
||||
llm:
|
||||
provider: openai
|
||||
model: gpt-4o
|
||||
|
||||
policy:
|
||||
block_on: high
|
||||
block_on: high # critical | high | medium | low | none
|
||||
min_confidence: medium
|
||||
categories:
|
||||
secrets: true
|
||||
injection: true
|
||||
# all categories on by default — set false to disable
|
||||
custom_rules:
|
||||
- "Never log PII or session tokens"
|
||||
|
||||
context:
|
||||
lines_before: 30
|
||||
max_files: 50
|
||||
max_diff_bytes: 500000
|
||||
|
||||
output:
|
||||
comment_on_pr: true
|
||||
annotate_lines: true
|
||||
fail_on_error: true
|
||||
```
|
||||
|
||||
### Key settings
|
||||
Full reference: [docs/configuration.md](docs/configuration.md) · Example: [.github/squidgate.yml.example](.github/squidgate.yml.example)
|
||||
|
||||
- `policy.block_on`: `critical` | `high` | `medium` | `low` | `none`
|
||||
- `llm.provider`: `openai` | `anthropic` | `azure` | `google` | `custom`
|
||||
- All categories under `policy.categories` are enabled by default.
|
||||
---
|
||||
|
||||
To relax, explicitly set `block_on: medium` or disable categories.
|
||||
## What it detects
|
||||
|
||||
## Action Inputs
|
||||
- Hardcoded secrets / API keys / private keys
|
||||
- SQL / command / XSS / SSRF / path traversal
|
||||
- Insecure deserialization
|
||||
- Broken authn / authz patterns
|
||||
- Weak crypto (MD5/SHA1 for security, ECB, hardcoded IVs)
|
||||
- Dangerous APIs (`eval`, `exec`, `pickle`, `yaml.load`, …)
|
||||
- Sensitive data in logs / errors
|
||||
- Patterns aligned with **OWASP Top 10**, **API Security Top 10**, **CWE Top 25**
|
||||
|
||||
| Input | Required | Default | Description |
|
||||
|-----------------|----------|----------------------------|------------------------------------------|
|
||||
| `github-token` | No | `${{ github.token }}` | Needs `checks:write`, `pull-requests:write` |
|
||||
| `llm-api-key` | Yes | — | Your LLM provider key (use secrets!) |
|
||||
| `config-path` | No | `.github/security-scan.yml`| Path to YAML config |
|
||||
| `llm-provider` | No | from config | Override provider |
|
||||
| `llm-model` | No | from config | Override model |
|
||||
| `block-on` | No | from config | Override severity threshold |
|
||||
| `llm-base-url` | No | — | For custom endpoints / Azure |
|
||||
---
|
||||
|
||||
## Supported Providers & Models (examples)
|
||||
## Action inputs
|
||||
|
||||
- **openai**: `gpt-4o`, `gpt-4o-mini`, `o1-preview` (use models that support JSON mode)
|
||||
- **anthropic**: `claude-3-5-sonnet-20241022`, `claude-3-opus-20240229`
|
||||
- **google**: `gemini-1.5-pro`, `gemini-1.5-flash`
|
||||
- **azure**: Set `llm-provider: azure` + `llm-base-url`
|
||||
- **custom**: Any OpenAI-compatible server (Ollama, vLLM, LiteLLM, local, etc.)
|
||||
| Input | Required | Default | Description |
|
||||
|-------|----------|---------|-------------|
|
||||
| `llm-api-key` | **Yes** | — | Provider API key |
|
||||
| `github-token` | No | `${{ github.token }}` | `checks` + `pull-requests` + `contents` |
|
||||
| `config-path` | No | `.github/squidgate.yml` | Config path |
|
||||
| `llm-provider` | No | config / `openai` | `openai` \| `anthropic` \| `azure` \| `google` \| `custom` |
|
||||
| `llm-model` | No | config / `gpt-4o` | Model id |
|
||||
| `llm-base-url` | No | — | Azure / custom / xAI URL |
|
||||
| `block-on` | No | config / `high` | Minimum failing severity |
|
||||
|
||||
## Outputs
|
||||
|
||||
- `findings-count`
|
||||
- `blocking-findings-count`
|
||||
- `conclusion`: `success` | `failure`
|
||||
| Output | Description |
|
||||
|--------|-------------|
|
||||
| `findings-count` | Findings after confidence filter |
|
||||
| `blocking-findings-count` | Findings ≥ `block_on` |
|
||||
| `conclusion` | `success` \| `failure` |
|
||||
|
||||
## Privacy & Security
|
||||
---
|
||||
|
||||
- Your code and diffs are sent **only** to the LLM endpoint you configure.
|
||||
- No data is stored by this action's maintainers.
|
||||
- Uses least-privilege permissions.
|
||||
- Supports private/self-hosted LLMs and self-hosted runners.
|
||||
## Privacy
|
||||
|
||||
- Diffs go **only** to the LLM endpoint **you** configure
|
||||
- SquidSec does **not** receive or store your code
|
||||
- Least-privilege permissions; self-hosted runners + private models supported
|
||||
|
||||
→ [docs/privacy.md](docs/privacy.md)
|
||||
|
||||
---
|
||||
|
||||
## How it works
|
||||
|
||||
```
|
||||
PR opened / updated
|
||||
│
|
||||
▼
|
||||
Unified diff (+ context)
|
||||
│
|
||||
▼
|
||||
Policy-aware prompts (temperature 0, JSON)
|
||||
│
|
||||
▼
|
||||
Your LLM
|
||||
│
|
||||
▼
|
||||
Filter → annotate → PR comment
|
||||
│
|
||||
▼
|
||||
Fail check if finding ≥ block_on
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Development
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run build:ts
|
||||
npm run package
|
||||
git clone https://github.com/SquidSec/SquidGate.git
|
||||
cd SquidGate
|
||||
npm ci
|
||||
npm test
|
||||
npm run build
|
||||
```
|
||||
|
||||
The bundled `dist/index.js` is what the action executes.
|
||||
See [docs/development.md](docs/development.md) · [CONTRIBUTING.md](CONTRIBUTING.md)
|
||||
|
||||
---
|
||||
|
||||
## SquidSec
|
||||
|
||||
Built by **[SquidSec](https://www.SquidOffense.com)** — security tooling that teams actually ship.
|
||||
|
||||
- [SquidOffense.com](https://www.SquidOffense.com)
|
||||
- [github.com/SquidSec](https://github.com/SquidSec)
|
||||
- [SquidScanner](https://github.com/DotNetRussell/SquidScanner) — AI attack-surface analysis
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
MIT (or your choice)
|
||||
[MIT](LICENSE) © SquidSec
|
||||
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
# Security policy
|
||||
|
||||
## Supported versions
|
||||
|
||||
| Version | Supported |
|
||||
|---------|-----------|
|
||||
| `v1.x` | Yes |
|
||||
| `main` | Best effort |
|
||||
| Older tags | No |
|
||||
|
||||
## Reporting a vulnerability
|
||||
|
||||
If you find a security issue in **SquidGate**:
|
||||
|
||||
1. **Do not** open a public issue for exploitable bugs.
|
||||
2. Contact maintainers via [SquidOffense.com](https://www.SquidOffense.com) / SquidSec org.
|
||||
3. Include: description, impact, repro, suggested fix.
|
||||
|
||||
We aim to acknowledge within **72 hours**.
|
||||
|
||||
## Scope
|
||||
|
||||
**In scope:** secret leakage from the action, unsafe handling of untrusted PR content, supply-chain issues in `dist/`.
|
||||
|
||||
**Out of scope:** LLM false negatives/positives (model quality), third-party provider issues.
|
||||
|
||||
## Safe harbor
|
||||
|
||||
Good-faith research that follows this policy is welcome.
|
||||
@@ -5,7 +5,7 @@ jest.mock('../src/llm');
|
||||
|
||||
describe('action claims via pieces', () => {
|
||||
it('filters and blocks according to policy (validates core security gate behavior)', () => {
|
||||
const cfg = loadConfig('.github/security-scan.yml.example');
|
||||
const cfg = loadConfig('.github/squidgate.yml.example');
|
||||
const findings = [
|
||||
{ confidence: 'high', severity: 'high' },
|
||||
{ confidence: 'medium', severity: 'medium' },
|
||||
|
||||
@@ -33,7 +33,7 @@ describe('checks', () => {
|
||||
expect(result.conclusion).toBe('failure');
|
||||
expect(result.blockingCount).toBe(1); // only the high one blocks on 'high'
|
||||
expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({
|
||||
name: 'security-scan',
|
||||
name: 'SquidGate',
|
||||
head_sha: 'sha123',
|
||||
conclusion: 'failure',
|
||||
}));
|
||||
|
||||
@@ -2,7 +2,7 @@ import { loadConfig, DEFAULT_CONFIG, shouldBlock, filterFindings } from '../src/
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
const tmpConfigPath = path.join(__dirname, 'temp-security-scan.yml');
|
||||
const tmpConfigPath = path.join(__dirname, 'temp-squidgate.yml');
|
||||
|
||||
describe('config', () => {
|
||||
afterEach(() => {
|
||||
|
||||
+7
-7
@@ -1,12 +1,12 @@
|
||||
name: 'security-scan'
|
||||
description: 'LLM-powered PR security gate. Analyzes diffs for security issues and blocks merges on high-severity findings.'
|
||||
author: 'Security Scan Contributors'
|
||||
name: 'SquidGate'
|
||||
description: 'LLM-powered PR security gate by SquidSec. Analyzes diffs and blocks merges on high-severity findings.'
|
||||
author: 'SquidSec'
|
||||
|
||||
inputs:
|
||||
config-path:
|
||||
description: 'Path to config file'
|
||||
required: false
|
||||
default: '.github/security-scan.yml'
|
||||
default: '.github/squidgate.yml'
|
||||
llm-provider:
|
||||
description: 'Override LLM provider (openai | anthropic | azure | google | custom)'
|
||||
required: false
|
||||
@@ -21,15 +21,15 @@ inputs:
|
||||
required: true
|
||||
default: ${{ github.token }}
|
||||
llm-api-key:
|
||||
description: 'LLM provider API key (recommended to use secrets)'
|
||||
description: 'LLM provider API key (use repository secrets)'
|
||||
required: true
|
||||
llm-base-url:
|
||||
description: 'Optional base URL for custom/OpenAI-compatible or Azure endpoint (advanced)'
|
||||
description: 'Optional base URL for custom/OpenAI-compatible or Azure endpoint'
|
||||
required: false
|
||||
|
||||
outputs:
|
||||
findings-count:
|
||||
description: 'Total number of findings reported by the LLM'
|
||||
description: 'Total number of findings after confidence filtering'
|
||||
blocking-findings-count:
|
||||
description: 'Number of findings that meet or exceed the block_on threshold'
|
||||
conclusion:
|
||||
|
||||
Vendored
+2
-2
@@ -34852,7 +34852,7 @@ async function createCheckRun(token, owner, repo, headSha, findings, summary, bl
|
||||
const check = await octokit.rest.checks.create({
|
||||
owner,
|
||||
repo,
|
||||
name: 'security-scan',
|
||||
name: 'SquidGate',
|
||||
head_sha: headSha,
|
||||
status: 'completed',
|
||||
conclusion: conclusion,
|
||||
@@ -35187,7 +35187,7 @@ async function run() {
|
||||
try {
|
||||
const token = core.getInput('github-token', { required: true });
|
||||
const apiKey = core.getInput('llm-api-key', { required: true });
|
||||
const configPath = core.getInput('config-path') || '.github/security-scan.yml';
|
||||
const configPath = core.getInput('config-path') || '.github/squidgate.yml';
|
||||
const overrideProvider = core.getInput('llm-provider');
|
||||
const overrideModel = core.getInput('llm-model');
|
||||
const overrideBlockOn = core.getInput('block-on');
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
# Configuration reference
|
||||
|
||||
**SquidGate** primary config: **`.github/squidgate.yml`**
|
||||
Action inputs override the same fields for one-off runs.
|
||||
|
||||
## Full schema
|
||||
|
||||
```yaml
|
||||
version: 1
|
||||
|
||||
llm:
|
||||
provider: openai # openai | anthropic | azure | google | custom
|
||||
model: gpt-4o
|
||||
|
||||
policy:
|
||||
block_on: high # critical | high | medium | low | none
|
||||
min_confidence: medium # high | medium | low
|
||||
categories:
|
||||
secrets: true
|
||||
injection: true
|
||||
authn_authz: true
|
||||
cryptography: true
|
||||
insecure_deserialization: true
|
||||
path_traversal: true
|
||||
ssrf: true
|
||||
xss: true
|
||||
csrf: true
|
||||
supply_chain: true
|
||||
hardcoded_credentials: true
|
||||
dangerous_functions: true
|
||||
misconfiguration: true
|
||||
custom_rules: []
|
||||
|
||||
context:
|
||||
lines_before: 30
|
||||
lines_after: 30
|
||||
max_files: 50
|
||||
max_diff_bytes: 500000
|
||||
|
||||
output:
|
||||
comment_on_pr: true
|
||||
annotate_lines: true
|
||||
fail_on_error: true
|
||||
```
|
||||
|
||||
## `policy.block_on`
|
||||
|
||||
| Value | Behavior |
|
||||
|-------|----------|
|
||||
| `critical` | Only critical findings fail |
|
||||
| `high` | **Default.** high + critical fail |
|
||||
| `medium` | medium and above fail |
|
||||
| `low` | almost everything fails |
|
||||
| `none` | Soft mode — report only |
|
||||
|
||||
## `policy.min_confidence`
|
||||
|
||||
| Value | Behavior |
|
||||
|-------|----------|
|
||||
| `high` | Only clear issues |
|
||||
| `medium` | **Default** |
|
||||
| `low` | Include speculative findings |
|
||||
|
||||
## Providers
|
||||
|
||||
| Provider | `llm-provider` | Notes |
|
||||
|----------|----------------|-------|
|
||||
| OpenAI | `openai` | JSON mode; e.g. `gpt-4o` |
|
||||
| Anthropic | `anthropic` | Claude 3.5+ |
|
||||
| Google | `google` | Gemini |
|
||||
| Azure OpenAI | `azure` | Set `llm-base-url` |
|
||||
| xAI Grok | `custom` | `llm-base-url: https://api.x.ai/v1` |
|
||||
| Ollama / vLLM / LiteLLM | `custom` | Your server URL |
|
||||
|
||||
## Custom rules
|
||||
|
||||
```yaml
|
||||
policy:
|
||||
custom_rules:
|
||||
- "Reject MD5 for password hashing"
|
||||
- "All user-facing HTML must be escaped"
|
||||
```
|
||||
|
||||
## Action input overrides
|
||||
|
||||
| Input | Overrides |
|
||||
|-------|-----------|
|
||||
| `llm-provider` | `llm.provider` |
|
||||
| `llm-model` | `llm.model` |
|
||||
| `llm-base-url` | endpoint (not stored in YAML) |
|
||||
| `block-on` | `policy.block_on` |
|
||||
| `config-path` | path to YAML |
|
||||
@@ -0,0 +1,53 @@
|
||||
# Development
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 20+
|
||||
- npm 10+
|
||||
|
||||
## Setup
|
||||
|
||||
```bash
|
||||
git clone https://github.com/SquidSec/SquidGate.git
|
||||
cd SquidGate
|
||||
npm ci
|
||||
```
|
||||
|
||||
## Scripts
|
||||
|
||||
| Command | Purpose |
|
||||
|---------|---------|
|
||||
| `npm test` | Unit tests |
|
||||
| `npm run test:coverage` | Coverage |
|
||||
| `npm run build:ts` | TypeScript → `lib/` |
|
||||
| `npm run package` | ncc → `dist/index.js` |
|
||||
| `npm run build` | compile + bundle |
|
||||
|
||||
**Always commit an updated `dist/`** after source changes.
|
||||
|
||||
## Layout
|
||||
|
||||
```
|
||||
src/
|
||||
index.ts # Entry — diff fetch, orchestration
|
||||
config.ts # YAML, defaults, filtering
|
||||
prompts.ts # System / user prompts
|
||||
llm.ts # Providers + JSON extraction
|
||||
checks.ts # Check Run + PR comments
|
||||
types.ts
|
||||
__tests__/
|
||||
dist/ # Published bundle (committed)
|
||||
action.yml
|
||||
```
|
||||
|
||||
## Releasing
|
||||
|
||||
```bash
|
||||
npm test && npm run build
|
||||
git add dist && git commit -m "build: refresh dist"
|
||||
git tag v1.0.1 && git push origin v1.0.1
|
||||
# optional major floating tag:
|
||||
git tag -f v1 && git push -f origin v1
|
||||
```
|
||||
|
||||
Consumers should pin `@v1` or a full SHA.
|
||||
@@ -0,0 +1,45 @@
|
||||
# Privacy & security
|
||||
|
||||
## What leaves your runner
|
||||
|
||||
On each PR, **SquidGate** sends:
|
||||
|
||||
1. The **unified diff** (truncated by `max_diff_bytes`)
|
||||
2. **File paths** and language hints
|
||||
3. Your **policy configuration**
|
||||
|
||||
to the **LLM HTTP endpoint you configure**. Nothing else.
|
||||
|
||||
## What SquidSec does *not* do
|
||||
|
||||
- No telemetry back to SquidSec
|
||||
- No code retention by the action maintainers
|
||||
- No training on your diffs
|
||||
- No third-party analytics
|
||||
|
||||
Your relationship is with **your** model provider. Use enterprise / zero-retention options where available.
|
||||
|
||||
## Permissions
|
||||
|
||||
```yaml
|
||||
permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
checks: write
|
||||
```
|
||||
|
||||
## Secrets
|
||||
|
||||
Store keys only in GitHub Actions secrets. Never commit API keys.
|
||||
|
||||
## Self-hosted & air-gapped
|
||||
|
||||
- Self-hosted runners
|
||||
- `llm-provider: custom` + `llm-base-url` → private model
|
||||
- Diff never needs to leave your network
|
||||
|
||||
## Supply chain
|
||||
|
||||
- Pre-built `dist/index.js` (ncc)
|
||||
- Pin `SquidSec/SquidGate@v1` or a full commit SHA
|
||||
- CI tests and verifies `dist/` on every push to `main`
|
||||
+14
-4
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "security-scan",
|
||||
"name": "squidgate",
|
||||
"version": "1.0.0",
|
||||
"description": "LLM-powered GitHub Action security gate for pull requests",
|
||||
"description": "SquidGate — LLM-powered GitHub Action PR security gate by SquidSec",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"build": "tsc && ncc build lib/index.js -o dist",
|
||||
@@ -18,10 +18,20 @@
|
||||
"sast",
|
||||
"llm",
|
||||
"pr-check",
|
||||
"owasp"
|
||||
"owasp",
|
||||
"squidsec",
|
||||
"squidgate"
|
||||
],
|
||||
"author": "security-scan contributors",
|
||||
"author": "SquidSec",
|
||||
"license": "MIT",
|
||||
"homepage": "https://github.com/SquidSec/SquidGate",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/SquidSec/SquidGate.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/SquidSec/SquidGate/issues"
|
||||
},
|
||||
"type": "commonjs",
|
||||
"dependencies": {
|
||||
"@actions/core": "^1.10.1",
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ export async function createCheckRun(
|
||||
const check = await octokit.rest.checks.create({
|
||||
owner,
|
||||
repo,
|
||||
name: 'security-scan',
|
||||
name: 'SquidGate',
|
||||
head_sha: headSha,
|
||||
status: 'completed',
|
||||
conclusion: conclusion as any,
|
||||
|
||||
+1
-1
@@ -122,7 +122,7 @@ async function run(): Promise<void> {
|
||||
const token = core.getInput('github-token', { required: true });
|
||||
const apiKey = core.getInput('llm-api-key', { required: true });
|
||||
|
||||
const configPath = core.getInput('config-path') || '.github/security-scan.yml';
|
||||
const configPath = core.getInput('config-path') || '.github/squidgate.yml';
|
||||
const overrideProvider = core.getInput('llm-provider');
|
||||
const overrideModel = core.getInput('llm-model');
|
||||
const overrideBlockOn = core.getInput('block-on') as any;
|
||||
|
||||
Reference in New Issue
Block a user