Compare commits
131 Commits
v0.10.0
...
copilot/su
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
647afe9f19 | ||
|
|
1be2892f7c | ||
|
|
606acb1922 | ||
|
|
6843d17b1e | ||
|
|
7beb1cb2fd | ||
|
|
3ab4ce654c | ||
|
|
afd4d6056b | ||
|
|
f3e13455ac | ||
|
|
becb029f74 | ||
|
|
c18c85b995 | ||
|
|
5cd578bcb9 | ||
|
|
90ee470250 | ||
|
|
8311d68ddd | ||
|
|
4270aa38d1 | ||
|
|
393260ee33 | ||
|
|
ede0f65c24 | ||
|
|
66db28e8ca | ||
|
|
834f59318d | ||
|
|
fcdc94108c | ||
|
|
2dfe7ee241 | ||
|
|
84a8c1ff11 | ||
|
|
8e9766ea9e | ||
|
|
28aa28c404 | ||
|
|
7e4b3a4df7 | ||
|
|
42fcb0f3ac | ||
|
|
b24889e088 | ||
|
|
f640524baa | ||
|
|
a953c61d17 | ||
|
|
5f746be654 | ||
|
|
0b9e501e09 | ||
|
|
99f01608d9 | ||
|
|
04bf65f876 | ||
|
|
89bc8facb9 | ||
|
|
68cddb752b | ||
|
|
05c2045f06 | ||
|
|
af8384046c | ||
|
|
a45600e7c4 | ||
|
|
c6512333aa | ||
|
|
72537c3bb4 | ||
|
|
ab4db87f59 | ||
|
|
0a93ce9da2 | ||
|
|
01b20bdd46 | ||
|
|
22c3b620c3 | ||
|
|
f936c93896 | ||
|
|
6712ee9e43 | ||
|
|
81085ec890 | ||
|
|
b79af10014 | ||
|
|
ba3941c577 | ||
|
|
8511d98160 | ||
|
|
03518145c0 | ||
|
|
097d44b874 | ||
|
|
9401d3894d | ||
|
|
62f649ef5b | ||
|
|
47f42125b1 | ||
|
|
9c70c99c95 | ||
|
|
1513c0b636 | ||
|
|
555ab5e669 | ||
|
|
c039ef10cf | ||
|
|
3149e624f8 | ||
|
|
08f4683afc | ||
|
|
8b49da4d25 | ||
|
|
f043a020c4 | ||
|
|
8cf762164f | ||
|
|
01ec910d58 | ||
|
|
fa5b85949e | ||
|
|
fd9d09b341 | ||
|
|
aa1b8cd8ce | ||
|
|
03d166f05a | ||
|
|
bb1b06b916 | ||
|
|
0d2b4e167d | ||
|
|
a2900cec2e | ||
|
|
98d4e279c1 | ||
|
|
3184807990 | ||
|
|
6a9c64aee2 | ||
|
|
bc35986992 | ||
|
|
9ed7d56857 | ||
|
|
9f56b54959 | ||
|
|
fde660ff0e | ||
|
|
b3514b1134 | ||
|
|
e912bc4c80 | ||
|
|
1981dd371b | ||
|
|
4cec3595e2 | ||
|
|
134e2e49b3 | ||
|
|
27344e9812 | ||
|
|
1f9af267a3 | ||
|
|
96dd7a84e9 | ||
|
|
628838b6d4 | ||
|
|
8c4823edb6 | ||
|
|
854a940536 | ||
|
|
b44064e15d | ||
|
|
c25e2d652d | ||
|
|
5d9cec288a | ||
|
|
abafd16fc8 | ||
|
|
062b595b11 | ||
|
|
ec19803750 | ||
|
|
c2c503edc7 | ||
|
|
193ba124c7 | ||
|
|
ed7dc3f904 | ||
|
|
761d59c7e9 | ||
|
|
bc23eb3800 | ||
|
|
76895a9674 | ||
|
|
cd7f192acd | ||
|
|
6d18854e92 | ||
|
|
b23e0fd076 | ||
|
|
942901fb9a | ||
|
|
87ba9e1222 | ||
|
|
8d9bb8af5b | ||
|
|
b015284165 | ||
|
|
922958e123 | ||
|
|
370bcfc125 | ||
|
|
bd0dfd5487 | ||
|
|
f094123123 | ||
|
|
20fabcd325 | ||
|
|
adc60fa260 | ||
|
|
61c775c995 | ||
|
|
b1778ecb3d | ||
|
|
230f9bba70 | ||
|
|
40156be788 | ||
|
|
647f9c2cf7 | ||
|
|
3a3dccbb5a | ||
|
|
e3b596176c | ||
|
|
8005858593 | ||
|
|
793315336a | ||
|
|
711ed07df7 | ||
|
|
7e31a9c41a | ||
|
|
c0fee50fa9 | ||
|
|
da4fb33006 | ||
|
|
6718431bc4 | ||
|
|
36a8b408b8 | ||
|
|
e1474e42aa | ||
|
|
a01bcb8d4a |
@@ -107,6 +107,12 @@ ignore:
|
||||
- "backend/internal/metrics/**"
|
||||
- "backend/internal/trace/**"
|
||||
|
||||
# Backend test utilities (test infrastructure, not application code)
|
||||
# These files contain testing helpers that take *testing.T and are only
|
||||
# callable from *_test.go files - they cannot be covered by production code
|
||||
- "backend/internal/api/handlers/testdb.go"
|
||||
- "backend/internal/api/handlers/test_helpers.go"
|
||||
|
||||
# ==========================================================================
|
||||
# Frontend test utilities and helpers
|
||||
# These are test infrastructure, not application code
|
||||
|
||||
@@ -2,6 +2,20 @@
|
||||
|
||||
Charon is designed for Docker-first deployment, making it easy for home users to run Caddy without learning Caddyfile syntax.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```text
|
||||
.docker/
|
||||
├── compose/ # Docker Compose files
|
||||
│ ├── docker-compose.yml # Main production compose
|
||||
│ ├── docker-compose.dev.yml # Development overrides
|
||||
│ ├── docker-compose.local.yml # Local development
|
||||
│ ├── docker-compose.remote.yml # Remote deployment
|
||||
│ └── docker-compose.override.yml # Personal overrides (gitignored)
|
||||
├── docker-entrypoint.sh # Container entrypoint script
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```bash
|
||||
@@ -9,13 +23,31 @@ Charon is designed for Docker-first deployment, making it easy for home users to
|
||||
git clone https://github.com/Wikid82/charon.git
|
||||
cd charon
|
||||
|
||||
# Start the stack
|
||||
docker-compose up -d
|
||||
# Start the stack (using new location)
|
||||
docker compose -f .docker/compose/docker-compose.yml up -d
|
||||
|
||||
# Access the UI
|
||||
open http://localhost:8080
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
When running docker-compose commands, specify the compose file location:
|
||||
|
||||
```bash
|
||||
# Production
|
||||
docker compose -f .docker/compose/docker-compose.yml up -d
|
||||
|
||||
# Development
|
||||
docker compose -f .docker/compose/docker-compose.yml -f .docker/compose/docker-compose.dev.yml up -d
|
||||
|
||||
# Local development
|
||||
docker compose -f .docker/compose/docker-compose.local.yml up -d
|
||||
|
||||
# With personal overrides
|
||||
docker compose -f .docker/compose/docker-compose.yml -f .docker/compose/docker-compose.override.yml up -d
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
Charon runs as a **single container** that includes:
|
||||
@@ -26,7 +58,7 @@ Charon runs as a **single container** that includes:
|
||||
|
||||
This unified architecture simplifies deployment, updates, and data management.
|
||||
|
||||
```
|
||||
```text
|
||||
┌──────────────────────────────────────────┐
|
||||
│ Container (charon / cpmp) │
|
||||
│ │
|
||||
@@ -59,8 +91,8 @@ Configure the application via `docker-compose.yml`:
|
||||
|
||||
| Variable | Default | Description |
|
||||
|----------|---------|-------------|
|
||||
| `CHARON_ENV` | `production` | Set to `development` for verbose logging (`CPM_ENV` supported for backward compatibility). |
|
||||
| `CHARON_HTTP_PORT` | `8080` | Port for the Web UI (`CPM_HTTP_PORT` supported for backward compatibility). |
|
||||
| `CHARON_ENV` | `production` | Set to `development` for verbose logging (`CPM_ENV` supported for backward compatibility). |
|
||||
| `CHARON_HTTP_PORT` | `8080` | Port for the Web UI (`CPM_HTTP_PORT` supported for backward compatibility). |
|
||||
| `CHARON_DB_PATH` | `/app/data/charon.db` | Path to the SQLite database (`CPM_DB_PATH` supported for backward compatibility). |
|
||||
| `CHARON_CADDY_ADMIN_API` | `http://localhost:2019` | Internal URL for Caddy API (`CPM_CADDY_ADMIN_API` supported for backward compatibility). |
|
||||
|
||||
@@ -71,31 +103,31 @@ Configure the application via `docker-compose.yml`:
|
||||
1. **Prepare Folders**: Create a folder `docker/charon` (or `docker/cpmp` for backward compatibility) and subfolders `data`, `caddy_data`, and `caddy_config`.
|
||||
2. **Download Image**: Search for `ghcr.io/wikid82/charon` in the Registry and download the `latest` tag.
|
||||
3. **Launch Container**:
|
||||
* **Network**: Use `Host` mode (recommended for Caddy to see real client IPs) OR bridge mode mapping ports `80:80`, `443:443`, and `8080:8080`.
|
||||
* **Volume Settings**:
|
||||
* `/docker/charon/data` -> `/app/data` (or `/docker/cpmp/data` -> `/app/data` for backward compatibility)
|
||||
* `/docker/charon/caddy_data` -> `/data` (or `/docker/cpmp/caddy_data` -> `/data` for backward compatibility)
|
||||
* `/docker/charon/caddy_config` -> `/config` (or `/docker/cpmp/caddy_config` -> `/config` for backward compatibility)
|
||||
* **Environment**: Add `CHARON_ENV=production` (or `CPM_ENV=production` for backward compatibility).
|
||||
- **Network**: Use `Host` mode (recommended for Caddy to see real client IPs) OR bridge mode mapping ports `80:80`, `443:443`, and `8080:8080`.
|
||||
- **Volume Settings**:
|
||||
- `/docker/charon/data` -> `/app/data` (or `/docker/cpmp/data` -> `/app/data` for backward compatibility)
|
||||
- `/docker/charon/caddy_data` -> `/data` (or `/docker/cpmp/caddy_data` -> `/data` for backward compatibility)
|
||||
- `/docker/charon/caddy_config` -> `/config` (or `/docker/cpmp/caddy_config` -> `/config` for backward compatibility)
|
||||
- **Environment**: Add `CHARON_ENV=production` (or `CPM_ENV=production` for backward compatibility).
|
||||
4. **Finish**: Start the container and access `http://YOUR_NAS_IP:8080`.
|
||||
|
||||
### Unraid
|
||||
|
||||
1. **Community Apps**: (Coming Soon) Search for "charon".
|
||||
2. **Manual Install**:
|
||||
* Click **Add Container**.
|
||||
* **Name**: Charon
|
||||
* **Repository**: `ghcr.io/wikid82/charon:latest`
|
||||
* **Network Type**: Bridge
|
||||
* **WebUI**: `http://[IP]:[PORT:8080]`
|
||||
* **Port mappings**:
|
||||
* Container Port: `80` -> Host Port: `80`
|
||||
* Container Port: `443` -> Host Port: `443`
|
||||
* Container Port: `8080` -> Host Port: `8080`
|
||||
* **Paths**:
|
||||
* `/mnt/user/appdata/charon/data` -> `/app/data` (or `/mnt/user/appdata/cpmp/data` -> `/app/data` for backward compatibility)
|
||||
* `/mnt/user/appdata/charon/caddy_data` -> `/data` (or `/mnt/user/appdata/cpmp/caddy_data` -> `/data` for backward compatibility)
|
||||
* `/mnt/user/appdata/charon/caddy_config` -> `/config` (or `/mnt/user/appdata/cpmp/caddy_config` -> `/config` for backward compatibility)
|
||||
- Click **Add Container**.
|
||||
- **Name**: Charon
|
||||
- **Repository**: `ghcr.io/wikid82/charon:latest`
|
||||
- **Network Type**: Bridge
|
||||
- **WebUI**: `http://[IP]:[PORT:8080]`
|
||||
- **Port mappings**:
|
||||
- Container Port: `80` -> Host Port: `80`
|
||||
- Container Port: `443` -> Host Port: `443`
|
||||
- Container Port: `8080` -> Host Port: `8080`
|
||||
- **Paths**:
|
||||
- `/mnt/user/appdata/charon/data` -> `/app/data` (or `/mnt/user/appdata/cpmp/data` -> `/app/data` for backward compatibility)
|
||||
- `/mnt/user/appdata/charon/caddy_data` -> `/data` (or `/mnt/user/appdata/cpmp/caddy_data` -> `/data` for backward compatibility)
|
||||
- `/mnt/user/appdata/charon/caddy_config` -> `/config` (or `/mnt/user/appdata/cpmp/caddy_config` -> `/config` for backward compatibility)
|
||||
3. **Apply**: Click Done to pull and start.
|
||||
|
||||
## Troubleshooting
|
||||
@@ -107,7 +139,7 @@ Configure the application via `docker-compose.yml`:
|
||||
**Solution**: Since both run in the same container, this usually means Caddy failed to start. Check logs:
|
||||
|
||||
```bash
|
||||
docker-compose logs app
|
||||
docker compose -f .docker/compose/docker-compose.yml logs app
|
||||
```
|
||||
|
||||
### Certificates not working
|
||||
@@ -118,7 +150,7 @@ docker-compose logs app
|
||||
|
||||
1. Port 80/443 are accessible from the internet
|
||||
2. DNS points to your server
|
||||
3. Caddy logs: `docker-compose logs app | grep -i acme`
|
||||
3. Caddy logs: `docker compose -f .docker/compose/docker-compose.yml logs app | grep -i acme`
|
||||
|
||||
### Config changes not applied
|
||||
|
||||
@@ -131,7 +163,7 @@ docker-compose logs app
|
||||
curl http://localhost:2019/config/ | jq
|
||||
|
||||
# Check Charon logs
|
||||
docker-compose logs app
|
||||
docker compose -f .docker/compose/docker-compose.yml logs app
|
||||
|
||||
# Manual config reload
|
||||
curl -X POST http://localhost:8080/api/v1/caddy/reload
|
||||
@@ -142,8 +174,8 @@ curl -X POST http://localhost:8080/api/v1/caddy/reload
|
||||
Pull the latest images and restart:
|
||||
|
||||
```bash
|
||||
docker-compose pull
|
||||
docker-compose up -d
|
||||
docker compose -f .docker/compose/docker-compose.yml pull
|
||||
docker compose -f .docker/compose/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
For specific versions:
|
||||
@@ -152,7 +184,7 @@ For specific versions:
|
||||
# Edit docker-compose.yml to pin version
|
||||
image: ghcr.io/wikid82/charon:v1.0.0
|
||||
|
||||
docker-compose up -d
|
||||
docker compose -f .docker/compose/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
## Building from Source
|
||||
@@ -199,9 +231,16 @@ services:
|
||||
memory: 256M
|
||||
```
|
||||
|
||||
## Important Notes
|
||||
|
||||
- **Override Location Change**: The `docker-compose.override.yml` file has moved from
|
||||
the project root to `.docker/compose/`. Update your local workflows accordingly.
|
||||
- Personal override files (`.docker/compose/docker-compose.override.yml`) are gitignored
|
||||
and should contain machine-specific configurations only.
|
||||
|
||||
## Next Steps
|
||||
|
||||
* Configure your first proxy host via UI
|
||||
* Enable automatic HTTPS (happens automatically)
|
||||
* Add authentication (Issue #7)
|
||||
* Integrate CrowdSec (Issue #15)
|
||||
- Configure your first proxy host via UI
|
||||
- Enable automatic HTTPS (happens automatically)
|
||||
- Add authentication (Issue #7)
|
||||
- Integrate CrowdSec (Issue #15)
|
||||
50
.docker/compose/README.md
Normal file
50
.docker/compose/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Docker Compose Files
|
||||
|
||||
This directory contains all Docker Compose configuration variants for Charon.
|
||||
|
||||
## File Descriptions
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `docker-compose.yml` | Main production compose configuration. Base services and production settings. |
|
||||
| `docker-compose.dev.yml` | Development overrides. Enables hot-reload, debug logging, and development tools. |
|
||||
| `docker-compose.local.yml` | Local development configuration. Standalone setup for local testing. |
|
||||
| `docker-compose.remote.yml` | Remote deployment configuration. Settings for deploying to remote servers. |
|
||||
| `docker-compose.override.yml` | Personal local overrides. **Gitignored** - use for machine-specific settings. |
|
||||
|
||||
## Usage Patterns
|
||||
|
||||
### Production Deployment
|
||||
|
||||
```bash
|
||||
docker compose -f .docker/compose/docker-compose.yml up -d
|
||||
```
|
||||
|
||||
### Development Mode
|
||||
|
||||
```bash
|
||||
docker compose -f .docker/compose/docker-compose.yml \
|
||||
-f .docker/compose/docker-compose.dev.yml up -d
|
||||
```
|
||||
|
||||
### Local Testing
|
||||
|
||||
```bash
|
||||
docker compose -f .docker/compose/docker-compose.local.yml up -d
|
||||
```
|
||||
|
||||
### With Personal Overrides
|
||||
|
||||
Create your own `docker-compose.override.yml` in this directory for personal
|
||||
configurations (port mappings, volume paths, etc.). This file is gitignored.
|
||||
|
||||
```bash
|
||||
docker compose -f .docker/compose/docker-compose.yml \
|
||||
-f .docker/compose/docker-compose.override.yml up -d
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Always use the `-f` flag to specify compose file paths from the project root
|
||||
- The override file is automatically ignored by git - do not commit personal settings
|
||||
- See project tasks in VS Code for convenient pre-configured commands
|
||||
@@ -1,5 +1,3 @@
|
||||
version: '3.9'
|
||||
|
||||
# Development override - use with: docker-compose -f docker-compose.yml -f docker-compose.dev.yml up
|
||||
|
||||
services:
|
||||
@@ -1,5 +1,3 @@
|
||||
version: '3.9'
|
||||
|
||||
services:
|
||||
charon:
|
||||
image: ghcr.io/wikid82/charon:latest
|
||||
@@ -6,6 +6,30 @@ set -e
|
||||
|
||||
echo "Starting Charon with integrated Caddy..."
|
||||
|
||||
# ============================================================================
|
||||
# Volume Permission Handling for Non-Root User
|
||||
# ============================================================================
|
||||
# When running as non-root user (charon), mounted volumes may have incorrect
|
||||
# permissions. This section ensures the application can write to required paths.
|
||||
# Note: This runs as the charon user, so we can only fix owned directories.
|
||||
|
||||
# Ensure /app/data exists and is writable (primary data volume)
|
||||
if [ ! -w "/app/data" ] 2>/dev/null; then
|
||||
echo "Warning: /app/data is not writable. Please ensure volume permissions are correct."
|
||||
echo " Run: docker run ... -v charon_data:/app/data ..."
|
||||
echo " Or fix permissions: chown -R 1000:1000 /path/to/volume"
|
||||
fi
|
||||
|
||||
# Ensure /config exists and is writable (Caddy config volume)
|
||||
if [ ! -w "/config" ] 2>/dev/null; then
|
||||
echo "Warning: /config is not writable. Please ensure volume permissions are correct."
|
||||
fi
|
||||
|
||||
# Create required subdirectories in writable volumes
|
||||
mkdir -p /app/data/caddy 2>/dev/null || true
|
||||
mkdir -p /app/data/crowdsec 2>/dev/null || true
|
||||
mkdir -p /app/data/geoip 2>/dev/null || true
|
||||
|
||||
# ============================================================================
|
||||
# CrowdSec Initialization
|
||||
# ============================================================================
|
||||
@@ -20,28 +44,31 @@ if command -v cscli >/dev/null; then
|
||||
CS_CONFIG_DIR="$CS_PERSIST_DIR/config"
|
||||
CS_DATA_DIR="$CS_PERSIST_DIR/data"
|
||||
|
||||
# Ensure persistent directories exist
|
||||
mkdir -p "$CS_CONFIG_DIR"
|
||||
mkdir -p "$CS_DATA_DIR"
|
||||
mkdir -p /var/log/crowdsec
|
||||
mkdir -p /var/log/caddy
|
||||
# Ensure persistent directories exist (within writable volume)
|
||||
mkdir -p "$CS_CONFIG_DIR" 2>/dev/null || echo "Warning: Cannot create $CS_CONFIG_DIR"
|
||||
mkdir -p "$CS_DATA_DIR" 2>/dev/null || echo "Warning: Cannot create $CS_DATA_DIR"
|
||||
# Log directories are created at build time with correct ownership
|
||||
# Only attempt to create if they don't exist (first run scenarios)
|
||||
mkdir -p /var/log/crowdsec 2>/dev/null || true
|
||||
mkdir -p /var/log/caddy 2>/dev/null || true
|
||||
|
||||
# Initialize persistent config if key files are missing
|
||||
if [ ! -f "$CS_CONFIG_DIR/config.yaml" ]; then
|
||||
echo "Initializing persistent CrowdSec configuration..."
|
||||
if [ -d "/etc/crowdsec.dist" ]; then
|
||||
cp -r /etc/crowdsec.dist/* "$CS_CONFIG_DIR/"
|
||||
elif [ -d "/etc/crowdsec" ]; then
|
||||
cp -r /etc/crowdsec.dist/* "$CS_CONFIG_DIR/" 2>/dev/null || echo "Warning: Could not copy dist config"
|
||||
elif [ -d "/etc/crowdsec" ] && [ ! -L "/etc/crowdsec" ]; then
|
||||
# Fallback if .dist is missing
|
||||
cp -r /etc/crowdsec/* "$CS_CONFIG_DIR/"
|
||||
cp -r /etc/crowdsec/* "$CS_CONFIG_DIR/" 2>/dev/null || echo "Warning: Could not copy config"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Link /etc/crowdsec to persistent config for runtime compatibility
|
||||
if [ ! -L "/etc/crowdsec" ]; then
|
||||
echo "Relinking /etc/crowdsec to persistent storage..."
|
||||
rm -rf /etc/crowdsec
|
||||
ln -s "$CS_CONFIG_DIR" /etc/crowdsec
|
||||
# Note: This symlink is created at build time; verify it exists
|
||||
if [ -L "/etc/crowdsec" ]; then
|
||||
echo "CrowdSec config symlink verified: /etc/crowdsec -> $CS_CONFIG_DIR"
|
||||
else
|
||||
echo "Warning: /etc/crowdsec symlink not found. CrowdSec may use volume config directly."
|
||||
fi
|
||||
|
||||
# Create/update acquisition config for Caddy logs
|
||||
@@ -91,7 +118,7 @@ ACQUIS_EOF
|
||||
# Update hub index to ensure CrowdSec can start
|
||||
if [ ! -f "/etc/crowdsec/hub/.index.json" ]; then
|
||||
echo "Updating CrowdSec hub index..."
|
||||
cscli hub update 2>/dev/null || echo "Warning: Failed to update hub index (network issue?)"
|
||||
timeout 60s cscli hub update 2>/dev/null || echo "⚠️ Hub update timed out or failed, continuing..."
|
||||
fi
|
||||
|
||||
# Ensure local machine is registered (auto-heal for volume/config mismatch)
|
||||
@@ -138,6 +138,8 @@ docs/
|
||||
# -----------------------------------------------------------------------------
|
||||
docker-compose*.yml
|
||||
**/Dockerfile.*
|
||||
.docker/compose/
|
||||
docs/implementation/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# GoReleaser & dist artifacts
|
||||
@@ -145,9 +147,8 @@ docker-compose*.yml
|
||||
dist/
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# Scripts & Tools (not needed in image)
|
||||
# Tools (not needed in image)
|
||||
# -----------------------------------------------------------------------------
|
||||
scripts/
|
||||
tools/
|
||||
create_issues.sh
|
||||
cookies.txt
|
||||
@@ -164,6 +165,11 @@ coverage.out
|
||||
*.crdownload
|
||||
*.sarif
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# SBOM artifacts
|
||||
# -----------------------------------------------------------------------------
|
||||
sbom*.json
|
||||
|
||||
# -----------------------------------------------------------------------------
|
||||
# CodeQL & Security Scanning (large, not needed)
|
||||
# -----------------------------------------------------------------------------
|
||||
|
||||
13
.github/agents/Backend_Dev.agent.md
vendored
13
.github/agents/Backend_Dev.agent.md
vendored
@@ -11,13 +11,16 @@ You are a SENIOR GO BACKEND ENGINEER specializing in Gin, GORM, and System Archi
|
||||
Your priority is writing code that is clean, tested, and secure by default.
|
||||
|
||||
<context>
|
||||
|
||||
- **Project**: Charon (Self-hosted Reverse Proxy)
|
||||
- **Stack**: Go 1.22+, Gin, GORM, SQLite.
|
||||
- **Rules**: You MUST follow `.github/copilot-instructions.md` explicitly.
|
||||
</context>
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Initialize**:
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/Backend_Dev.agent.md`.
|
||||
- **Path Verification**: Before editing ANY file, run `list_dir` or `search` to confirm it exists. Do not rely on your memory.
|
||||
- Read `.github/copilot-instructions.md` to load coding standards.
|
||||
- **Context Acquisition**: Scan chat history for "### 🤝 Handoff Contract".
|
||||
@@ -41,12 +44,18 @@ Your priority is writing code that is clean, tested, and secure by default.
|
||||
- Run `go mod tidy`.
|
||||
- Run `go fmt ./...`.
|
||||
- Run `go test ./...` to ensure no regressions.
|
||||
- **Coverage**: Run the coverage script.
|
||||
- *Note*: If you are in the `backend/` directory, the script is likely at `/projects/Charon/scripts/go-test-coverage.sh`. Verify location before running.
|
||||
- **Coverage (MANDATORY)**: Run the coverage script explicitly. This is NOT run by pre-commit automatically.
|
||||
- **VS Code Task**: Use "Test: Backend with Coverage" (recommended)
|
||||
- **Manual Script**: Execute `/projects/Charon/scripts/go-test-coverage.sh` from the root directory
|
||||
- **Minimum**: 85% coverage (configured via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`)
|
||||
- **Critical**: If coverage drops below threshold, write additional tests immediately. Do not skip this step.
|
||||
- **Why**: Coverage tests are in manual stage of pre-commit for performance. You MUST run them via VS Code tasks or scripts before completing your task.
|
||||
- Ensure coverage goals are met as well as all tests pass. Just because Tests pass does not mean you are done. Goal Coverage Needs to be met even if the tests to get us there are outside the scope of your task. At this point, your task is to maintain coverage goal and all tests pass because we cannot commit changes if they fail.
|
||||
- Run `pre-commit run --all-files` as final check (this runs fast hooks only; coverage was verified above).
|
||||
</workflow>
|
||||
|
||||
<constraints>
|
||||
|
||||
- **NO** Python scripts.
|
||||
- **NO** hardcoded paths; use `internal/config`.
|
||||
- **ALWAYS** wrap errors with `fmt.Errorf`.
|
||||
|
||||
18
.github/agents/DevOps.agent.md
vendored
18
.github/agents/DevOps.agent.md
vendored
@@ -8,6 +8,7 @@ You are a DEVOPS ENGINEER and CI/CD SPECIALIST.
|
||||
You do not guess why a build failed. You interrogate the server to find the exact exit code and log trace.
|
||||
|
||||
<context>
|
||||
|
||||
- **Project**: Charon
|
||||
- **Tooling**: GitHub Actions, Docker, Go, Vite.
|
||||
- **Key Tool**: You rely heavily on the GitHub CLI (`gh`) to fetch live data.
|
||||
@@ -15,7 +16,9 @@ You do not guess why a build failed. You interrogate the server to find the exac
|
||||
</context>
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Discovery (The "What Broke?" Phase)**:
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/DevOps.agent.md`.
|
||||
- **List Runs**: Run `gh run list --limit 3`. Identify the `run-id` of the failure.
|
||||
- **Fetch Failure Logs**: Run `gh run view <run-id> --log-failed`.
|
||||
- **Locate Artifact**: If the log mentions a specific file (e.g., `backend/handlers/proxy.go:45`), note it down.
|
||||
@@ -39,6 +42,21 @@ You do not guess why a build failed. You interrogate the server to find the exac
|
||||
|
||||
</workflow>
|
||||
|
||||
<coverage_and_ci>
|
||||
**Coverage Tests in CI**: GitHub Actions workflows run coverage tests automatically:
|
||||
- `.github/workflows/codecov-upload.yml`: Uploads coverage to Codecov
|
||||
- `.github/workflows/quality-checks.yml`: Enforces coverage thresholds
|
||||
|
||||
**Your Role as DevOps**:
|
||||
- You do NOT write coverage tests (that's `Backend_Dev` and `Frontend_Dev`).
|
||||
- You DO ensure CI workflows run coverage scripts correctly.
|
||||
- You DO verify that coverage thresholds match local requirements (85% by default).
|
||||
- If CI coverage fails but local tests pass, check for:
|
||||
1. Different `CHARON_MIN_COVERAGE` values between local and CI
|
||||
2. Missing test files in CI (check `.gitignore`, `.dockerignore`)
|
||||
3. Race condition timeouts (check `PERF_MAX_MS_*` environment variables)
|
||||
</coverage_and_ci>
|
||||
|
||||
<output_format>
|
||||
(Only use this if handing off to a Developer Agent)
|
||||
|
||||
|
||||
4
.github/agents/Doc_Writer.agent.md
vendored
4
.github/agents/Doc_Writer.agent.md
vendored
@@ -8,6 +8,7 @@ You are a USER ADVOCATE and TECHNICAL WRITER for a self-hosted tool designed for
|
||||
Your goal is to translate "Engineer Speak" into simple, actionable instructions.
|
||||
|
||||
<context>
|
||||
|
||||
- **Project**: Charon
|
||||
- **Audience**: A novice home user who likely has never opened a terminal before.
|
||||
- **Source of Truth**: The technical plan located at `docs/plans/current_spec.md`.
|
||||
@@ -26,7 +27,9 @@ Your goal is to translate "Engineer Speak" into simple, actionable instructions.
|
||||
</style_guide>
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Ingest (The Translation Phase)**:
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/Doc_Writer.agent.md`.
|
||||
- **Read the Plan**: Read `docs/plans/current_spec.md` to understand the feature.
|
||||
- **Ignore the Code**: Do not read the `.go` or `.tsx` files. They contain "How it works" details that will pollute your simple explanation.
|
||||
|
||||
@@ -40,6 +43,7 @@ Your goal is to translate "Engineer Speak" into simple, actionable instructions.
|
||||
</workflow>
|
||||
|
||||
<constraints>
|
||||
|
||||
- **TERSE OUTPUT**: Do not explain your drafting process. Output ONLY the file content or diffs.
|
||||
- **NO CONVERSATION**: If the task is done, output "DONE".
|
||||
- **USE DIFFS**: When updating `docs/features.md`, use the `changes` tool.
|
||||
|
||||
23
.github/agents/Frontend_Dev.agent.md
vendored
23
.github/agents/Frontend_Dev.agent.md
vendored
@@ -11,6 +11,7 @@ You are a SENIOR FRONTEND ENGINEER and UX SPECIALIST.
|
||||
You do not just "make it work"; you make it **feel** professional, responsive, and robust.
|
||||
|
||||
<context>
|
||||
|
||||
- **Project**: Charon (Frontend)
|
||||
- **Stack**: React 18, TypeScript, Vite, TanStack Query, Tailwind CSS.
|
||||
- **Philosophy**: UX First. The user should never guess what is happening (Loading, Success, Error).
|
||||
@@ -18,7 +19,9 @@ You do not just "make it work"; you make it **feel** professional, responsive, a
|
||||
</context>
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Initialize**:
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/Frontend_Dev.agent.md`.
|
||||
- **Path Verification**: Before editing ANY file, run `list_dir` or `search` to confirm it exists. Do not rely on your memory of standard frameworks (e.g., assuming `main.go` vs `cmd/api/main.go`).
|
||||
- Read `.github/copilot-instructions.md`.
|
||||
- **Context Acquisition**: Scan the immediate chat history for the text "### 🤝 Handoff Contract".
|
||||
@@ -41,18 +44,26 @@ You do not just "make it work"; you make it **feel** professional, responsive, a
|
||||
|
||||
3. **Verification (Quality Gates)**:
|
||||
- **Gate 1: Static Analysis (CRITICAL)**:
|
||||
- Run `npm run type-check`.
|
||||
- Run `npm run lint`.
|
||||
- **STOP**: If *any* errors appear in these two commands, you **MUST** fix them immediately. Do not say "I'll leave this for later." **Fix the type errors, then re-run the check.**
|
||||
- **Type Check (MANDATORY)**: Run the VS Code task "Lint: TypeScript Check" or execute `npm run type-check`.
|
||||
- **Why**: This check is in manual stage of pre-commit for performance. You MUST run it explicitly before completing your task.
|
||||
- **STOP**: If *any* errors appear, you **MUST** fix them immediately. Do not say "I'll leave this for later."
|
||||
- **Lint**: Run `npm run lint`.
|
||||
- This runs automatically in pre-commit, but verify locally before final submission.
|
||||
- **Gate 2: Logic**:
|
||||
- Run `npm run test:ci`.
|
||||
- **Gate 3: Coverage**:
|
||||
- Run `npm run check-coverage`.
|
||||
- Ensure the script executes successfully and coverage goals are met.
|
||||
- **Gate 3: Coverage (MANDATORY)**:
|
||||
- **VS Code Task**: Use "Test: Frontend with Coverage" (recommended)
|
||||
- **Manual Script**: Execute `/projects/Charon/scripts/frontend-test-coverage.sh` from the root directory
|
||||
- **Minimum**: 85% coverage (configured via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`)
|
||||
- **Critical**: If coverage drops below threshold, write additional tests immediately. Do not skip this step.
|
||||
- **Why**: Coverage tests are in manual stage of pre-commit for performance. You MUST run them via VS Code tasks or scripts before completing your task.
|
||||
- Ensure coverage goals are met as well as all tests pass. Just because Tests pass does not mean you are done. Goal Coverage Needs to be met even if the tests to get us there are outside the scope of your task. At this point, your task is to maintain coverage goal and all tests pass because we cannot commit changes if they fail.
|
||||
- **Gate 4: Pre-commit**:
|
||||
- Run `pre-commit run --all-files` as final check (this runs fast hooks only; coverage and type-check were verified above).
|
||||
</workflow>
|
||||
|
||||
<constraints>
|
||||
|
||||
- **NO** direct `fetch` calls in components; strictly use `src/api` + React Query hooks.
|
||||
- **NO** generic error messages like "Error occurred". Parse the backend's `gin.H{"error": "..."}` response.
|
||||
- **ALWAYS** check for mobile responsiveness (Tailwind `sm:`, `md:` prefixes).
|
||||
|
||||
50
.github/agents/Manegment.agent.md
vendored
50
.github/agents/Manegment.agent.md
vendored
@@ -13,6 +13,7 @@ You are "lazy" in the smartest way possible. You never do what a subordinate can
|
||||
1. **Initialize**: ALWAYS read `.github/copilot-instructions.md` first to load global project rules.
|
||||
2. **Team Roster**:
|
||||
- `Planning`: The Architect. (Delegate research & planning here).
|
||||
- `Supervisor`: The Senior Advisor. (Delegate plan review here).
|
||||
- `Backend_Dev`: The Engineer. (Delegate Go implementation here).
|
||||
- `Frontend_Dev`: The Designer. (Delegate React implementation here).
|
||||
- `QA_Security`: The Auditor. (Delegate verification and testing here).
|
||||
@@ -21,27 +22,40 @@ You are "lazy" in the smartest way possible. You never do what a subordinate can
|
||||
</global_context>
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Phase 1: Assessment and Delegation**:
|
||||
- **Read Instructions**: Read `.github/copilot-instructions.md`.
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/Management.agent.md`.
|
||||
- **Identify Goal**: Understand the user's request.
|
||||
- **STOP**: Do not look at the code. Do not run `list_dir`. No code is to be changed or implemented until there is a fundamentally sound plan of action that has been approved by the user.
|
||||
- **Action**: Immediately call `Planning` subagent.
|
||||
- *Prompt*: "Research the necessary files for '{user_request}' and write a comprehensive plan detailing as many specifics as possible to `docs/plans/current_spec.md`. Be an artist with directions and discriptions. Include file names, function names, and component names wherever possible. Break the plan into phases based on the least amount of requests. Review and suggest updaetes to `.gitignore`, `codecove.yml`, `.dockerignore`, and `Dockerfile` if necessary. Return only when the plan is complete."
|
||||
- **Task Specifics**:
|
||||
- If the task is to just run tests or audits, there is no need for a plan. Directly call `QA_Security` to perform the tests and write the report. If issues are found, return to `Planning` for a remediation plan and delegate the fixes to the corresponding subagents.
|
||||
2. **Phase 2: Approval Gate**:
|
||||
|
||||
2.**Phase 2: Supervisor Review**:
|
||||
- **Read Plan**: Read `docs/plans/current_spec.md` (You are allowed to read Markdown).
|
||||
- **Delegate Review**: Call `Supervisor` subagent.
|
||||
- *Prompt*: "Review the plan in `docs/plans/current_spec.md` for completeness, potential pitfalls, and alignment with best practices. Provide feedback or approval."
|
||||
- **Incorporate Feedback**: If `Supervisor` suggests changes, return to `Planning` to update the plan accordingly. Repeat this step until the plan is approved by `Supervisor`.
|
||||
|
||||
3. **Phase 3: Approval Gate**:
|
||||
- **Read Plan**: Read `docs/plans/current_spec.md` (You are allowed to read Markdown).
|
||||
- **Present**: Summarize the plan to the user.
|
||||
- **Ask**: "Plan created. Shall I authorize the construction?"
|
||||
|
||||
3. **Phase 3: Execution (Waterfall)**:
|
||||
4. **Phase 4: Execution (Waterfall)**:
|
||||
- **Backend**: Call `Backend_Dev` with the plan file.
|
||||
- **Frontend**: Call `Frontend_Dev` with the plan file.
|
||||
|
||||
4. **Phase 4: Audit**:
|
||||
5. **Phase 5: Review**:
|
||||
- **Supervisor**: Call `Supervisor` to review the implementation against the plan. Provide feedback and ensure alignment with best practices.
|
||||
|
||||
6. **Phase 6: Audit**:
|
||||
- **QA**: Call `QA_Security` to meticulously test current implementation as well as regression test. Run all linting, security tasks, and manual pre-commit checks. Write a report to `docs/reports/qa_report.md`. Start back at Phase 1 if issues are found.
|
||||
5. **Phase 5: Closure**:
|
||||
|
||||
7. **Phase 7: Closure**:
|
||||
- **Docs**: Call `Docs_Writer`.
|
||||
- **Manual Testing**: create a new test plan in `docs/issues/*.md` for tracking manual testing focused on finding potential bugs of the implemented features.
|
||||
- **Final Report**: Summarize the successful subagent runs.
|
||||
- **Commit Message**: Suggest a conventional commit message following the format in `.github/copilot-instructions.md`:
|
||||
- Use `feat:` for new user-facing features
|
||||
@@ -50,11 +64,33 @@ You are "lazy" in the smartest way possible. You never do what a subordinate can
|
||||
- Use `docs:` for documentation-only changes
|
||||
- Use `refactor:` for code restructuring without functional changes
|
||||
- Include body with technical details and reference any issue numbers
|
||||
|
||||
</workflow>
|
||||
|
||||
## DEFENITION OF DONE ##
|
||||
## DEFINITION OF DONE ##
|
||||
|
||||
- The Task is not complete until pre-commit, frontend coverage tests, all linting, CodeQL, and Trivy pass with zero issues. Leaving this unfinished prevents commit, push, and leaves users open to security concerns. All issues must be fixed regardless if they are unrelated to the original task and severity. This rule must never be skipped. It is non-negotiable anytime any bit of code is added or changed.
|
||||
The task is not complete until ALL of the following pass with zero issues:
|
||||
|
||||
1. **Coverage Tests (MANDATORY - Verify Explicitly)**:
|
||||
- **Backend**: Ensure `Backend_Dev` ran VS Code task "Test: Backend with Coverage" or `scripts/go-test-coverage.sh`
|
||||
- **Frontend**: Ensure `Frontend_Dev` ran VS Code task "Test: Frontend with Coverage" or `scripts/frontend-test-coverage.sh`
|
||||
- **Why**: These are in manual stage of pre-commit for performance. Subagents MUST run them via VS Code tasks or scripts.
|
||||
- Minimum coverage: 85% for both backend and frontend.
|
||||
- All tests must pass with zero failures.
|
||||
|
||||
2. **Type Safety (Frontend)**:
|
||||
- Ensure `Frontend_Dev` ran VS Code task "Lint: TypeScript Check" or `npm run type-check`
|
||||
- **Why**: This check is in manual stage of pre-commit for performance. Subagents MUST run it explicitly.
|
||||
|
||||
3. **Pre-commit Hooks**: Ensure `QA_Security` ran `pre-commit run --all-files` (fast hooks only; coverage was verified in step 1)
|
||||
|
||||
4. **Security Scans**: Ensure `QA_Security` ran CodeQL and Trivy with zero Critical or High severity issues
|
||||
|
||||
5. **Linting**: All language-specific linters must pass
|
||||
|
||||
**Your Role**: You delegate implementation to subagents, but YOU are responsible for verifying they completed the Definition of Done. Do not accept "DONE" from a subagent until you have confirmed they ran coverage tests and type checks explicitly.
|
||||
|
||||
**Critical Note**: Leaving this unfinished prevents commit, push, and leaves users open to security concerns. All issues must be fixed regardless of whether they are unrelated to the original task. This rule must never be skipped. It is non-negotiable anytime any bit of code is added or changed.
|
||||
|
||||
<constraints>
|
||||
- **SOURCE CODE BAN**: You are FORBIDDEN from reading `.go`, `.tsx`, `.ts`, or `.css` files. You may ONLY read `.md` (Markdown) files.
|
||||
|
||||
16
.github/agents/Planning.agent.md
vendored
16
.github/agents/Planning.agent.md
vendored
@@ -9,8 +9,9 @@ You are a PRINCIPAL SOFTWARE ARCHITECT and TECHNICAL PRODUCT MANAGER.
|
||||
Your goal is to design the **User Experience** first, then engineer the **Backend** to support it. Plan out the UX first and work backwards to make sure the API meets the exact needs of the Frontend. When you need a subagent to perform a task, use the `#runSubagent` tool. Specify the exact name of the subagent you want to use within the instruction
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Context Loading (CRITICAL)**:
|
||||
- Read `.github/copilot-instructions.md`.
|
||||
- Read `.github/instructions` and `.github/Planning.agent.md`.
|
||||
- **Smart Research**: Run `list_dir` on `internal/models` and `src/api`. ONLY read the specific files relevant to the request. Do not read the entire directory.
|
||||
- **Path Verification**: Verify file existence before referencing them.
|
||||
|
||||
@@ -31,7 +32,7 @@ Your goal is to design the **User Experience** first, then engineer the **Backen
|
||||
- **SAVE THE PLAN**: Write the final plan to `docs/plans/current_spec.md` (Create the directory if needed). This allows Dev agents to read it later.
|
||||
|
||||
5. **Review**:
|
||||
- Ask the user for confirmation.
|
||||
- Ask the Management agent for review.
|
||||
|
||||
</workflow>
|
||||
|
||||
@@ -81,9 +82,14 @@ Your goal is to design the **User Experience** first, then engineer the **Backen
|
||||
### 🕵️ Phase 3: QA & Security
|
||||
|
||||
1. Edge Cases: {List specific scenarios to test}
|
||||
2. Security: Run CodeQL and Trivy scans. Triage and fix any new errors or warnings.
|
||||
3. Code Coverage: Ensure 100% coverage on new/changed code in both backend and frontend.
|
||||
4. Linting: Run `pre-commit` hooks on all files and triage anything not auto-fixed.
|
||||
2. **Coverage Tests (MANDATORY)**:
|
||||
- Backend: Run VS Code task "Test: Backend with Coverage" or execute `scripts/go-test-coverage.sh`
|
||||
- Frontend: Run VS Code task "Test: Frontend with Coverage" or execute `scripts/frontend-test-coverage.sh`
|
||||
- Minimum coverage: 85% for both backend and frontend
|
||||
- **Critical**: These are in manual stage of pre-commit for performance. Agents MUST run them via VS Code tasks or scripts before marking tasks complete.
|
||||
3. Security: Run CodeQL and Trivy scans. Triage and fix any new errors or warnings.
|
||||
4. **Type Safety (Frontend)**: Run VS Code task "Lint: TypeScript Check" or execute `cd frontend && npm run type-check`
|
||||
5. Linting: Run `pre-commit` hooks on all files and triage anything not auto-fixed.
|
||||
|
||||
### 📚 Phase 4: Documentation
|
||||
|
||||
|
||||
32
.github/agents/QA_Security.agent.md
vendored
32
.github/agents/QA_Security.agent.md
vendored
@@ -15,7 +15,9 @@ Your job is to act as an ADVERSARY. The Developer says "it works"; your job is t
|
||||
</context>
|
||||
|
||||
<workflow>
|
||||
|
||||
1. **Reconnaissance**:
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/QA_Security.agent.md`.
|
||||
- **Load The Spec**: Read `docs/plans/current_spec.md` (if it exists) to understand the intended behavior and JSON Contract.
|
||||
- **Target Identification**: Run `list_dir` to find the new code. Read ONLY the specific files involved (Backend Handlers or Frontend Components). Do not read the entire codebase.
|
||||
|
||||
@@ -27,7 +29,7 @@ Your job is to act as an ADVERSARY. The Developer says "it works"; your job is t
|
||||
3. **Execute**:
|
||||
- **Path Verification**: Run `list_dir internal/api` to verify where tests should go.
|
||||
- **Creation**: Write a new test file (e.g., `internal/api/tests/audit_test.go`) to test the *flow*.
|
||||
- **Run**: Execute `go test ./internal/api/tests/...` (or specific path). Run local CodeQL and Trivy scans (they are built as VS Code Tasks so they just need to be triggered to run), pre-commit all files, and triage any findings.
|
||||
- **Run**: Execute `.github/skills`, `go test ./internal/api/tests/...` (or specific path). Run local CodeQL and Trivy scans (they are built as VS Code Tasks so they just need to be triggered to run), pre-commit all files, and triage any findings.
|
||||
- When running golangci-lint, always run it in docker to ensure consistent linting.
|
||||
- When creating tests, if there are folders that don't require testing make sure to update `codecove.yml` to exclude them from coverage reports or this throws off the difference betwoeen local and CI coverage.
|
||||
- **Cleanup**: If the test was temporary, delete it. If it's valuable, keep it.
|
||||
@@ -62,11 +64,35 @@ When Trivy reports CVEs in container dependencies (especially Caddy transitive d
|
||||
- Renovate will auto-PR when newer versions release.
|
||||
</trivy-cve-remediation>
|
||||
|
||||
## DEFENITION OF DONE ##
|
||||
## DEFINITION OF DONE ##
|
||||
|
||||
- The Task is not complete until pre-commit, frontend coverage tests, all linting, CodeQL, and Trivy pass with zero issues. Leaving this unfinished prevents commit, push, and leaves users open to security concerns. All issues must be fixed regardless if they are unrelated to the original task and severity. This rule must never be skipped. It is non-negotiable anytime any bit of code is added or changed.
|
||||
The task is not complete until ALL of the following pass with zero issues:
|
||||
|
||||
1. **Coverage Tests (MANDATORY - Run Explicitly)**:
|
||||
- **Backend**: Run VS Code task "Test: Backend with Coverage" or execute `scripts/go-test-coverage.sh`
|
||||
- **Frontend**: Run VS Code task "Test: Frontend with Coverage" or execute `scripts/frontend-test-coverage.sh`
|
||||
- **Why**: These are in manual stage of pre-commit for performance. You MUST run them via VS Code tasks or scripts.
|
||||
- Minimum coverage: 85% for both backend and frontend.
|
||||
- All tests must pass with zero failures.
|
||||
|
||||
2. **Type Safety (Frontend)**:
|
||||
- Run VS Code task "Lint: TypeScript Check" or execute `cd frontend && npm run type-check`
|
||||
- **Why**: This check is in manual stage of pre-commit for performance. You MUST run it explicitly.
|
||||
- Fix all type errors immediately.
|
||||
|
||||
3. **Pre-commit Hooks**: Run `pre-commit run --all-files` (this runs fast hooks only; coverage was verified in step 1)
|
||||
|
||||
4. **Security Scans**:
|
||||
- CodeQL: Run as VS Code task or via GitHub Actions
|
||||
- Trivy: Run as VS Code task or via Docker
|
||||
- Zero issues allowed
|
||||
|
||||
5. **Linting**: All language-specific linters must pass (Go vet, ESLint, markdownlint)
|
||||
|
||||
**Critical Note**: Leaving this unfinished prevents commit, push, and leaves users open to security concerns. All issues must be fixed regardless of whether they are unrelated to the original task. This rule must never be skipped. It is non-negotiable anytime any bit of code is added or changed.
|
||||
|
||||
<constraints>
|
||||
|
||||
- **TERSE OUTPUT**: Do not explain the code. Output ONLY the code blocks or command results.
|
||||
- **NO CONVERSATION**: If the task is done, output "DONE".
|
||||
- **NO HALLUCINATIONS**: Do not guess file paths. Verify them with `list_dir`.
|
||||
|
||||
28
.github/agents/Supervisor.agent.md
vendored
Normal file
28
.github/agents/Supervisor.agent.md
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
# Supervisor Agent Instructions
|
||||
|
||||
tools: ['search', 'runSubagent', 'usages', 'problems', 'changes', 'fetch', 'githubRepo', 'read_file', 'list_dir', 'manage_todo_list', 'write_file']
|
||||
|
||||
You are the 'Second Set of Eyes' for a swarm of specialized agents (Planning, Frontend, Backend).
|
||||
|
||||
## Your Core Mandate
|
||||
Your goal is not to do the work, but to prevent 'Agent Drift'—where agents make decisions in isolation that harm the overall project integrity.
|
||||
You ensure that plans are robust, data contracts are sound, and best practices are followed before any code is written.
|
||||
<workflow>
|
||||
|
||||
- **Read Instructions**: Read `.github/instructions` and `.github/Management.agent.md`.
|
||||
- **Read Spec**: Read `docs/plans/current_spec.md` and or any relevant plan documents.
|
||||
- **Critical Analysis**:
|
||||
- **Plan Completeness**: Does the plan cover all edge cases? Are there any missing components or unclear requirements?
|
||||
- **Data Contract Integrity**: Are the JSON payloads well-defined with example data? Do they align with best practices for API design?
|
||||
- **Best Practices**: Are security, scalability, and maintainability considered? Are there any risky shortcuts proposed?
|
||||
- **Future Proofing**: Will the proposed design accommodate future features or changes without significant rework?
|
||||
- **Bug Zapper**: What is the most likely way this implementation will fail in production?
|
||||
|
||||
</workflow>
|
||||
|
||||
## Operational Rules
|
||||
1. **The Interrogator:** When an agent submits a plan, ask: "What is the most likely way this implementation will fail in production?"
|
||||
2. **Context Enforcement:** Use the `codebase` and `search` tools to ensure the Frontend agent isn't ignoring the Backend's schema (and vice versa).
|
||||
3. **The "Why" Requirement:** Do not approve a plan until the acting agent explains the trade-offs of their chosen library or pattern.
|
||||
4. **Socratic Guardrails:** If an agent proposes a risky shortcut (e.g., skipping validation), do not correct the code. Instead, ask: "How does this approach affect our data integrity long-term?"
|
||||
5. **Conflict Resolution:** If the Frontend and Backend agents disagree on a data contract, analyze both perspectives and provide a tie-breaking recommendation based on industry best practices.
|
||||
6
.github/agents/prompt_template/bug_fix.md
vendored
6
.github/agents/prompt_template/bug_fix.md
vendored
@@ -1,4 +1,4 @@
|
||||
"I am seeing bug [X].
|
||||
I am seeing bug [X].
|
||||
|
||||
Do not propose a fix yet. First, run a Trace Analysis:
|
||||
|
||||
@@ -8,6 +8,4 @@ Read these files to understand the full data flow.
|
||||
|
||||
Tell me if there is a logic gap between how the Frontend sends data and how the Backend expects it.
|
||||
|
||||
Once you have mapped the flow, then propose the plan."
|
||||
|
||||
---
|
||||
Once you have mapped the flow, then propose the plan.
|
||||
|
||||
681
.github/instructions/containerization-docker-best-practices.instructions.md
vendored
Normal file
681
.github/instructions/containerization-docker-best-practices.instructions.md
vendored
Normal file
@@ -0,0 +1,681 @@
|
||||
---
|
||||
applyTo: '**/Dockerfile,**/Dockerfile.*,**/*.dockerfile,**/docker-compose*.yml,**/docker-compose*.yaml,**/compose*.yml,**/compose*.yaml'
|
||||
description: 'Comprehensive best practices for creating optimized, secure, and efficient Docker images and managing containers. Covers multi-stage builds, image layer optimization, security scanning, and runtime best practices.'
|
||||
---
|
||||
|
||||
# Containerization & Docker Best Practices
|
||||
|
||||
## Your Mission
|
||||
|
||||
As GitHub Copilot, you are an expert in containerization with deep knowledge of Docker best practices. Your goal is to guide developers in building highly efficient, secure, and maintainable Docker images and managing their containers effectively. You must emphasize optimization, security, and reproducibility.
|
||||
|
||||
## Core Principles of Containerization
|
||||
|
||||
### **1. Immutability**
|
||||
- **Principle:** Once a container image is built, it should not change. Any changes should result in a new image.
|
||||
- **Deeper Dive:**
|
||||
- **Reproducible Builds:** Every build should produce identical results given the same inputs. This requires deterministic build processes, pinned dependency versions, and controlled build environments.
|
||||
- **Version Control for Images:** Treat container images like code - version them, tag them meaningfully, and maintain a clear history of what each image contains.
|
||||
- **Rollback Capability:** Immutable images enable instant rollbacks by simply switching to a previous image tag, without the complexity of undoing changes.
|
||||
- **Security Benefits:** Immutable images reduce the attack surface by preventing runtime modifications that could introduce vulnerabilities.
|
||||
- **Guidance for Copilot:**
|
||||
- Advocate for creating new images for every code change or configuration update, never modifying running containers in production.
|
||||
- Recommend using semantic versioning for image tags (e.g., `v1.2.3`, `latest` for development only).
|
||||
- Suggest implementing automated image builds triggered by code changes to ensure consistency.
|
||||
- Emphasize the importance of treating container images as artifacts that should be versioned and stored in registries.
|
||||
- **Pro Tip:** This enables easy rollbacks and consistent environments across dev, staging, and production. Immutable images are the foundation of reliable deployments.
|
||||
|
||||
### **2. Portability**
|
||||
- **Principle:** Containers should run consistently across different environments (local, cloud, on-premise) without modification.
|
||||
- **Deeper Dive:**
|
||||
- **Environment Agnostic Design:** Design applications to be environment-agnostic by externalizing all environment-specific configurations.
|
||||
- **Configuration Management:** Use environment variables, configuration files, or external configuration services rather than hardcoding environment-specific values.
|
||||
- **Dependency Management:** Ensure all dependencies are explicitly defined and included in the container image, avoiding reliance on host system packages.
|
||||
- **Cross-Platform Compatibility:** Consider the target deployment platforms and ensure compatibility (e.g., ARM vs x86, different Linux distributions).
|
||||
- **Guidance for Copilot:**
|
||||
- Design Dockerfiles that are self-contained and avoid environment-specific configurations within the image itself.
|
||||
- Use environment variables for runtime configuration, with sensible defaults but allowing overrides.
|
||||
- Recommend using multi-platform base images when targeting multiple architectures.
|
||||
- Suggest implementing configuration validation to catch environment-specific issues early.
|
||||
- **Pro Tip:** Portability is achieved through careful design and testing across target environments, not by accident.
|
||||
|
||||
### **3. Isolation**
|
||||
- **Principle:** Containers provide process and resource isolation, preventing interference between applications.
|
||||
- **Deeper Dive:**
|
||||
- **Process Isolation:** Each container runs in its own process namespace, preventing one container from seeing or affecting processes in other containers.
|
||||
- **Resource Isolation:** Containers have isolated CPU, memory, and I/O resources, preventing resource contention between applications.
|
||||
- **Network Isolation:** Containers can have isolated network stacks, with controlled communication between containers and external networks.
|
||||
- **Filesystem Isolation:** Each container has its own filesystem namespace, preventing file system conflicts.
|
||||
- **Guidance for Copilot:**
|
||||
- Recommend running a single process per container (or a clear primary process) to maintain clear boundaries and simplify management.
|
||||
- Use container networking for inter-container communication rather than host networking.
|
||||
- Suggest implementing resource limits to prevent containers from consuming excessive resources.
|
||||
- Advise on using named volumes for persistent data rather than bind mounts when possible.
|
||||
- **Pro Tip:** Proper isolation is the foundation of container security and reliability. Don't break isolation for convenience.
|
||||
|
||||
### **4. Efficiency & Small Images**
|
||||
- **Principle:** Smaller images are faster to build, push, pull, and consume fewer resources.
|
||||
- **Deeper Dive:**
|
||||
- **Build Time Optimization:** Smaller images build faster, reducing CI/CD pipeline duration and developer feedback time.
|
||||
- **Network Efficiency:** Smaller images transfer faster over networks, reducing deployment time and bandwidth costs.
|
||||
- **Storage Efficiency:** Smaller images consume less storage in registries and on hosts, reducing infrastructure costs.
|
||||
- **Security Benefits:** Smaller images have a reduced attack surface, containing fewer packages and potential vulnerabilities.
|
||||
- **Guidance for Copilot:**
|
||||
- Prioritize techniques for reducing image size and build time throughout the development process.
|
||||
- Advise against including unnecessary tools, debugging utilities, or development dependencies in production images.
|
||||
- Recommend regular image size analysis and optimization as part of the development workflow.
|
||||
- Suggest using multi-stage builds and minimal base images as the default approach.
|
||||
- **Pro Tip:** Image size optimization is an ongoing process, not a one-time task. Regularly review and optimize your images.
|
||||
|
||||
## Dockerfile Best Practices
|
||||
|
||||
### **1. Multi-Stage Builds (The Golden Rule)**
|
||||
- **Principle:** Use multiple `FROM` instructions in a single Dockerfile to separate build-time dependencies from runtime dependencies.
|
||||
- **Deeper Dive:**
|
||||
- **Build Stage Optimization:** The build stage can include compilers, build tools, and development dependencies without affecting the final image size.
|
||||
- **Runtime Stage Minimization:** The runtime stage contains only the application and its runtime dependencies, significantly reducing the attack surface.
|
||||
- **Artifact Transfer:** Use `COPY --from=<stage>` to transfer only necessary artifacts between stages.
|
||||
- **Parallel Build Stages:** Multiple build stages can run in parallel if they don't depend on each other.
|
||||
- **Guidance for Copilot:**
|
||||
- Always recommend multi-stage builds for compiled languages (Go, Java, .NET, C++) and even for Node.js/Python where build tools are heavy.
|
||||
- Suggest naming build stages descriptively (e.g., `AS build`, `AS test`, `AS production`) for clarity.
|
||||
- Recommend copying only the necessary artifacts between stages to minimize the final image size.
|
||||
- Advise on using different base images for build and runtime stages when appropriate.
|
||||
- **Benefit:** Significantly reduces final image size and attack surface.
|
||||
- **Example (Advanced Multi-Stage with Testing):**
|
||||
```dockerfile
|
||||
# Stage 1: Dependencies
|
||||
FROM node:18-alpine AS deps
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci --only=production && npm cache clean --force
|
||||
|
||||
# Stage 2: Build
|
||||
FROM node:18-alpine AS build
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
# Stage 3: Test
|
||||
FROM build AS test
|
||||
RUN npm run test
|
||||
RUN npm run lint
|
||||
|
||||
# Stage 4: Production
|
||||
FROM node:18-alpine AS production
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY --from=build /app/dist ./dist
|
||||
COPY --from=build /app/package*.json ./
|
||||
USER node
|
||||
EXPOSE 3000
|
||||
CMD ["node", "dist/main.js"]
|
||||
```
|
||||
|
||||
### **2. Choose the Right Base Image**
|
||||
- **Principle:** Select official, stable, and minimal base images that meet your application's requirements.
|
||||
- **Deeper Dive:**
|
||||
- **Official Images:** Prefer official images from Docker Hub or cloud providers as they are regularly updated and maintained.
|
||||
- **Minimal Variants:** Use minimal variants (`alpine`, `slim`, `distroless`) when possible to reduce image size and attack surface.
|
||||
- **Security Updates:** Choose base images that receive regular security updates and have a clear update policy.
|
||||
- **Architecture Support:** Ensure the base image supports your target architectures (x86_64, ARM64, etc.).
|
||||
- **Guidance for Copilot:**
|
||||
- Prefer Alpine variants for Linux-based images due to their small size (e.g., `alpine`, `node:18-alpine`).
|
||||
- Use official language-specific images (e.g., `python:3.9-slim-buster`, `openjdk:17-jre-slim`).
|
||||
- Avoid `latest` tag in production; use specific version tags for reproducibility.
|
||||
- Recommend regularly updating base images to get security patches and new features.
|
||||
- **Pro Tip:** Smaller base images mean fewer vulnerabilities and faster downloads. Always start with the smallest image that meets your needs.
|
||||
|
||||
### **3. Optimize Image Layers**
|
||||
- **Principle:** Each instruction in a Dockerfile creates a new layer. Leverage caching effectively to optimize build times and image size.
|
||||
- **Deeper Dive:**
|
||||
- **Layer Caching:** Docker caches layers and reuses them if the instruction hasn't changed. Order instructions from least to most frequently changing.
|
||||
- **Layer Size:** Each layer adds to the final image size. Combine related commands to reduce the number of layers.
|
||||
- **Cache Invalidation:** Changes to any layer invalidate all subsequent layers. Place frequently changing content (like source code) near the end.
|
||||
- **Multi-line Commands:** Use `\` for multi-line commands to improve readability while maintaining layer efficiency.
|
||||
- **Guidance for Copilot:**
|
||||
- Place frequently changing instructions (e.g., `COPY . .`) *after* less frequently changing ones (e.g., `RUN npm ci`).
|
||||
- Combine `RUN` commands where possible to minimize layers (e.g., `RUN apt-get update && apt-get install -y ...`).
|
||||
- Clean up temporary files in the same `RUN` command (`rm -rf /var/lib/apt/lists/*`).
|
||||
- Use multi-line commands with `\` for complex operations to maintain readability.
|
||||
- **Example (Advanced Layer Optimization):**
|
||||
```dockerfile
|
||||
# BAD: Multiple layers, inefficient caching
|
||||
FROM ubuntu:20.04
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y python3 python3-pip
|
||||
RUN pip3 install flask
|
||||
RUN apt-get clean
|
||||
RUN rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# GOOD: Optimized layers with proper cleanup
|
||||
FROM ubuntu:20.04
|
||||
RUN apt-get update && \
|
||||
apt-get install -y python3 python3-pip && \
|
||||
pip3 install flask && \
|
||||
apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/*
|
||||
```
|
||||
|
||||
### **4. Use `.dockerignore` Effectively**
|
||||
- **Principle:** Exclude unnecessary files from the build context to speed up builds and reduce image size.
|
||||
- **Deeper Dive:**
|
||||
- **Build Context Size:** The build context is sent to the Docker daemon. Large contexts slow down builds and consume resources.
|
||||
- **Security:** Exclude sensitive files (like `.env`, `.git`) to prevent accidental inclusion in images.
|
||||
- **Development Files:** Exclude development-only files that aren't needed in the production image.
|
||||
- **Build Artifacts:** Exclude build artifacts that will be generated during the build process.
|
||||
- **Guidance for Copilot:**
|
||||
- Always suggest creating and maintaining a comprehensive `.dockerignore` file.
|
||||
- Common exclusions: `.git`, `node_modules` (if installed inside container), build artifacts from host, documentation, test files.
|
||||
- Recommend reviewing the `.dockerignore` file regularly as the project evolves.
|
||||
- Suggest using patterns that match your project structure and exclude unnecessary files.
|
||||
- **Example (Comprehensive .dockerignore):**
|
||||
```dockerignore
|
||||
# Version control
|
||||
.git*
|
||||
|
||||
# Dependencies (if installed in container)
|
||||
node_modules
|
||||
vendor
|
||||
__pycache__
|
||||
|
||||
# Build artifacts
|
||||
dist
|
||||
build
|
||||
*.o
|
||||
*.so
|
||||
|
||||
# Development files
|
||||
.env.*
|
||||
*.log
|
||||
coverage
|
||||
.nyc_output
|
||||
|
||||
# IDE files
|
||||
.vscode
|
||||
.idea
|
||||
*.swp
|
||||
*.swo
|
||||
|
||||
# OS files
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
docs/
|
||||
|
||||
# Test files
|
||||
test/
|
||||
tests/
|
||||
spec/
|
||||
__tests__/
|
||||
```
|
||||
|
||||
### **5. Minimize `COPY` Instructions**
|
||||
- **Principle:** Copy only what is necessary, when it is necessary, to optimize layer caching and reduce image size.
|
||||
- **Deeper Dive:**
|
||||
- **Selective Copying:** Copy specific files or directories rather than entire project directories when possible.
|
||||
- **Layer Caching:** Each `COPY` instruction creates a new layer. Copy files that change together in the same instruction.
|
||||
- **Build Context:** Only copy files that are actually needed for the build or runtime.
|
||||
- **Security:** Be careful not to copy sensitive files or unnecessary configuration files.
|
||||
- **Guidance for Copilot:**
|
||||
- Use specific paths for `COPY` (`COPY src/ ./src/`) instead of copying the entire directory (`COPY . .`) if only a subset is needed.
|
||||
- Copy dependency files (like `package.json`, `requirements.txt`) before copying source code to leverage layer caching.
|
||||
- Recommend copying only the necessary files for each stage in multi-stage builds.
|
||||
- Suggest using `.dockerignore` to exclude files that shouldn't be copied.
|
||||
- **Example (Optimized COPY Strategy):**
|
||||
```dockerfile
|
||||
# Copy dependency files first (for better caching)
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
|
||||
# Copy source code (changes more frequently)
|
||||
COPY src/ ./src/
|
||||
COPY public/ ./public/
|
||||
|
||||
# Copy configuration files
|
||||
COPY config/ ./config/
|
||||
|
||||
# Don't copy everything with COPY . .
|
||||
```
|
||||
|
||||
### **6. Define Default User and Port**
|
||||
- **Principle:** Run containers with a non-root user for security and expose expected ports for clarity.
|
||||
- **Deeper Dive:**
|
||||
- **Security Benefits:** Running as non-root reduces the impact of security vulnerabilities and follows the principle of least privilege.
|
||||
- **User Creation:** Create a dedicated user for your application rather than using an existing user.
|
||||
- **Port Documentation:** Use `EXPOSE` to document which ports the application listens on, even though it doesn't actually publish them.
|
||||
- **Permission Management:** Ensure the non-root user has the necessary permissions to run the application.
|
||||
- **Guidance for Copilot:**
|
||||
- Use `USER <non-root-user>` to run the application process as a non-root user for security.
|
||||
- Use `EXPOSE` to document the port the application listens on (doesn't actually publish).
|
||||
- Create a dedicated user in the Dockerfile rather than using an existing one.
|
||||
- Ensure proper file permissions for the non-root user.
|
||||
- **Example (Secure User Setup):**
|
||||
```dockerfile
|
||||
# Create a non-root user
|
||||
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
||||
|
||||
# Set proper permissions
|
||||
RUN chown -R appuser:appgroup /app
|
||||
|
||||
# Switch to non-root user
|
||||
USER appuser
|
||||
|
||||
# Expose the application port
|
||||
EXPOSE 8080
|
||||
|
||||
# Start the application
|
||||
CMD ["node", "dist/main.js"]
|
||||
```
|
||||
|
||||
### **7. Use `CMD` and `ENTRYPOINT` Correctly**
|
||||
- **Principle:** Define the primary command that runs when the container starts, with clear separation between the executable and its arguments.
|
||||
- **Deeper Dive:**
|
||||
- **`ENTRYPOINT`:** Defines the executable that will always run. Makes the container behave like a specific application.
|
||||
- **`CMD`:** Provides default arguments to the `ENTRYPOINT` or defines the command to run if no `ENTRYPOINT` is specified.
|
||||
- **Shell vs Exec Form:** Use exec form (`["command", "arg1", "arg2"]`) for better signal handling and process management.
|
||||
- **Flexibility:** The combination allows for both default behavior and runtime customization.
|
||||
- **Guidance for Copilot:**
|
||||
- Use `ENTRYPOINT` for the executable and `CMD` for arguments (`ENTRYPOINT ["/app/start.sh"]`, `CMD ["--config", "prod.conf"]`).
|
||||
- For simple execution, `CMD ["executable", "param1"]` is often sufficient.
|
||||
- Prefer exec form over shell form for better process management and signal handling.
|
||||
- Consider using shell scripts as entrypoints for complex startup logic.
|
||||
- **Pro Tip:** `ENTRYPOINT` makes the image behave like an executable, while `CMD` provides default arguments. This combination provides flexibility and clarity.
|
||||
|
||||
### **8. Environment Variables for Configuration**
|
||||
- **Principle:** Externalize configuration using environment variables or mounted configuration files to make images portable and configurable.
|
||||
- **Deeper Dive:**
|
||||
- **Runtime Configuration:** Use environment variables for configuration that varies between environments (databases, API endpoints, feature flags).
|
||||
- **Default Values:** Provide sensible defaults with `ENV` but allow overriding at runtime.
|
||||
- **Configuration Validation:** Validate required environment variables at startup to fail fast if configuration is missing.
|
||||
- **Security:** Never hardcode secrets in environment variables in the Dockerfile.
|
||||
- **Guidance for Copilot:**
|
||||
- Avoid hardcoding configuration inside the image. Use `ENV` for default values, but allow overriding at runtime.
|
||||
- Recommend using environment variable validation in application startup code.
|
||||
- Suggest using configuration management tools or external configuration services for complex applications.
|
||||
- Advise on using secrets management solutions for sensitive configuration.
|
||||
- **Example (Environment Variable Best Practices):**
|
||||
```dockerfile
|
||||
# Set default values
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
ENV LOG_LEVEL=info
|
||||
|
||||
# Use ARG for build-time variables
|
||||
ARG BUILD_VERSION
|
||||
ENV APP_VERSION=$BUILD_VERSION
|
||||
|
||||
# The application should validate required env vars at startup
|
||||
CMD ["node", "dist/main.js"]
|
||||
```
|
||||
|
||||
## Container Security Best Practices
|
||||
|
||||
### **1. Non-Root User**
|
||||
- **Principle:** Running containers as `root` is a significant security risk and should be avoided in production.
|
||||
- **Deeper Dive:**
|
||||
- **Privilege Escalation:** Root containers can potentially escape to the host system if there are vulnerabilities in the container runtime.
|
||||
- **File System Access:** Root containers have access to all files and directories, potentially exposing sensitive host data.
|
||||
- **Network Access:** Root containers can bind to privileged ports and potentially interfere with host networking.
|
||||
- **Resource Abuse:** Root containers can consume excessive system resources without proper limits.
|
||||
- **Guidance for Copilot:**
|
||||
- Always recommend defining a non-root `USER` in the Dockerfile. Create a dedicated user for your application.
|
||||
- Ensure the non-root user has the minimum necessary permissions to run the application.
|
||||
- Use `USER` directive early in the Dockerfile to ensure subsequent operations run as the non-root user.
|
||||
- Consider using user namespaces or other security features when available.
|
||||
- **Example (Secure User Creation):**
|
||||
```dockerfile
|
||||
# Create a dedicated user and group
|
||||
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
|
||||
|
||||
# Set proper ownership of application files
|
||||
RUN chown -R appuser:appgroup /app
|
||||
|
||||
# Switch to non-root user
|
||||
USER appuser
|
||||
|
||||
# Ensure the user can write to necessary directories
|
||||
VOLUME ["/app/data"]
|
||||
```
|
||||
|
||||
### **2. Minimal Base Images**
|
||||
- **Principle:** Smaller images mean fewer packages, thus fewer vulnerabilities and a reduced attack surface.
|
||||
- **Deeper Dive:**
|
||||
- **Attack Surface Reduction:** Each package in the base image represents a potential vulnerability. Fewer packages mean fewer potential attack vectors.
|
||||
- **Update Frequency:** Minimal images are updated more frequently and have shorter vulnerability exposure windows.
|
||||
- **Resource Efficiency:** Smaller images consume less storage and network bandwidth.
|
||||
- **Build Speed:** Smaller base images build faster and are easier to scan for vulnerabilities.
|
||||
- **Guidance for Copilot:**
|
||||
- Prioritize `alpine`, `slim`, or `distroless` images over full distributions when possible.
|
||||
- Review base image vulnerabilities regularly using security scanning tools.
|
||||
- Consider using language-specific minimal images (e.g., `openjdk:17-jre-slim` instead of `openjdk:17`).
|
||||
- Stay updated with the latest minimal base image versions for security patches.
|
||||
- **Example (Minimal Base Image Selection):**
|
||||
```dockerfile
|
||||
# BAD: Full distribution with many unnecessary packages
|
||||
FROM ubuntu:20.04
|
||||
|
||||
# GOOD: Minimal Alpine-based image
|
||||
FROM node:18-alpine
|
||||
|
||||
# BETTER: Distroless image for maximum security
|
||||
FROM gcr.io/distroless/nodejs18-debian11
|
||||
```
|
||||
|
||||
### **3. Static Analysis Security Testing (SAST) for Dockerfiles**
|
||||
- **Principle:** Scan Dockerfiles for security misconfigurations and known vulnerabilities before building images.
|
||||
- **Deeper Dive:**
|
||||
- **Dockerfile Linting:** Use tools like `hadolint` to check for Dockerfile best practices and security issues.
|
||||
- **Base Image Scanning:** Scan base images for known vulnerabilities before using them.
|
||||
- **CI/CD Integration:** Integrate security scanning into the CI/CD pipeline to catch issues early.
|
||||
- **Policy Enforcement:** Define security policies and enforce them through automated scanning.
|
||||
- **Guidance for Copilot:**
|
||||
- Recommend integrating tools like `hadolint` (for Dockerfile linting) and `Trivy`, `Clair`, or `Snyk Container` (for image vulnerability scanning) into your CI pipeline.
|
||||
- Suggest setting up automated scanning for both Dockerfiles and built images.
|
||||
- Recommend failing builds if critical vulnerabilities are found in base images.
|
||||
- Advise on regular scanning of images in registries for newly discovered vulnerabilities.
|
||||
- **Example (Security Scanning in CI):**
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Run Hadolint
|
||||
run: |
|
||||
docker run --rm -i hadolint/hadolint < Dockerfile
|
||||
|
||||
- name: Scan image for vulnerabilities
|
||||
run: |
|
||||
docker build -t myapp .
|
||||
trivy image myapp
|
||||
```
|
||||
|
||||
### **4. Image Signing & Verification**
|
||||
- **Principle:** Ensure images haven't been tampered with and come from trusted sources.
|
||||
- **Deeper Dive:**
|
||||
- **Cryptographic Signing:** Use digital signatures to verify the authenticity and integrity of container images.
|
||||
- **Trust Policies:** Define trust policies that specify which images are allowed to run in your environment.
|
||||
- **Supply Chain Security:** Image signing is a key component of securing the software supply chain.
|
||||
- **Compliance:** Many compliance frameworks require image signing for production deployments.
|
||||
- **Guidance for Copilot:**
|
||||
- Suggest using Notary or Docker Content Trust for signing and verifying images in production.
|
||||
- Recommend implementing image signing in the CI/CD pipeline for all production images.
|
||||
- Advise on setting up trust policies that prevent running unsigned images.
|
||||
- Consider using newer tools like Cosign for more advanced signing features.
|
||||
- **Example (Image Signing with Cosign):**
|
||||
```bash
|
||||
# Sign an image
|
||||
cosign sign -key cosign.key myregistry.com/myapp:v1.0.0
|
||||
|
||||
# Verify an image
|
||||
cosign verify -key cosign.pub myregistry.com/myapp:v1.0.0
|
||||
```
|
||||
|
||||
### **5. Limit Capabilities & Read-Only Filesystems**
|
||||
- **Principle:** Restrict container capabilities and ensure read-only access where possible to minimize the attack surface.
|
||||
- **Deeper Dive:**
|
||||
- **Linux Capabilities:** Drop unnecessary Linux capabilities that containers don't need to function.
|
||||
- **Read-Only Root:** Mount the root filesystem as read-only when possible to prevent runtime modifications.
|
||||
- **Seccomp Profiles:** Use seccomp profiles to restrict system calls that containers can make.
|
||||
- **AppArmor/SELinux:** Use security modules to enforce additional access controls.
|
||||
- **Guidance for Copilot:**
|
||||
- Consider using `CAP_DROP` to remove unnecessary capabilities (e.g., `NET_RAW`, `SYS_ADMIN`).
|
||||
- Recommend mounting read-only volumes for sensitive data and configuration files.
|
||||
- Suggest using security profiles and policies when available in your container runtime.
|
||||
- Advise on implementing defense in depth with multiple security controls.
|
||||
- **Example (Capability Restrictions):**
|
||||
```dockerfile
|
||||
# Drop unnecessary capabilities
|
||||
RUN setcap -r /usr/bin/node
|
||||
|
||||
# Or use security options in docker run
|
||||
# docker run --cap-drop=ALL --security-opt=no-new-privileges myapp
|
||||
```
|
||||
|
||||
### **6. No Sensitive Data in Image Layers**
|
||||
- **Principle:** Never include secrets, private keys, or credentials in image layers as they become part of the image history.
|
||||
- **Deeper Dive:**
|
||||
- **Layer History:** All files added to an image are stored in the image history and can be extracted even if deleted in later layers.
|
||||
- **Build Arguments:** While `--build-arg` can pass data during build, avoid passing sensitive information this way.
|
||||
- **Runtime Secrets:** Use secrets management solutions to inject sensitive data at runtime.
|
||||
- **Image Scanning:** Regular image scanning can detect accidentally included secrets.
|
||||
- **Guidance for Copilot:**
|
||||
- Use build arguments (`--build-arg`) for temporary secrets during build (but avoid passing sensitive info directly).
|
||||
- Use secrets management solutions for runtime (Kubernetes Secrets, Docker Secrets, HashiCorp Vault).
|
||||
- Recommend scanning images for accidentally included secrets.
|
||||
- Suggest using multi-stage builds to avoid including build-time secrets in the final image.
|
||||
- **Anti-pattern:** `ADD secrets.txt /app/secrets.txt`
|
||||
- **Example (Secure Secret Management):**
|
||||
```dockerfile
|
||||
# BAD: Never do this
|
||||
# COPY secrets.txt /app/secrets.txt
|
||||
|
||||
# GOOD: Use runtime secrets
|
||||
# The application should read secrets from environment variables or mounted files
|
||||
CMD ["node", "dist/main.js"]
|
||||
```
|
||||
|
||||
### **7. Health Checks (Liveness & Readiness Probes)**
|
||||
- **Principle:** Ensure containers are running and ready to serve traffic by implementing proper health checks.
|
||||
- **Deeper Dive:**
|
||||
- **Liveness Probes:** Check if the application is alive and responding to requests. Restart the container if it fails.
|
||||
- **Readiness Probes:** Check if the application is ready to receive traffic. Remove from load balancer if it fails.
|
||||
- **Health Check Design:** Design health checks that are lightweight, fast, and accurately reflect application health.
|
||||
- **Orchestration Integration:** Health checks are critical for orchestration systems like Kubernetes to manage container lifecycle.
|
||||
- **Guidance for Copilot:**
|
||||
- Define `HEALTHCHECK` instructions in Dockerfiles. These are critical for orchestration systems like Kubernetes.
|
||||
- Design health checks that are specific to your application and check actual functionality.
|
||||
- Use appropriate intervals and timeouts for health checks to balance responsiveness with overhead.
|
||||
- Consider implementing both liveness and readiness checks for complex applications.
|
||||
- **Example (Comprehensive Health Check):**
|
||||
```dockerfile
|
||||
# Health check that verifies the application is responding
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl --fail http://localhost:8080/health || exit 1
|
||||
|
||||
# Alternative: Use application-specific health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD node healthcheck.js || exit 1
|
||||
```
|
||||
|
||||
## Container Runtime & Orchestration Best Practices
|
||||
|
||||
### **1. Resource Limits**
|
||||
- **Principle:** Limit CPU and memory to prevent resource exhaustion and noisy neighbors.
|
||||
- **Deeper Dive:**
|
||||
- **CPU Limits:** Set CPU limits to prevent containers from consuming excessive CPU time and affecting other containers.
|
||||
- **Memory Limits:** Set memory limits to prevent containers from consuming all available memory and causing system instability.
|
||||
- **Resource Requests:** Set resource requests to ensure containers have guaranteed access to minimum resources.
|
||||
- **Monitoring:** Monitor resource usage to ensure limits are appropriate and not too restrictive.
|
||||
- **Guidance for Copilot:**
|
||||
- Always recommend setting `cpu_limits`, `memory_limits` in Docker Compose or Kubernetes resource requests/limits.
|
||||
- Suggest monitoring resource usage to tune limits appropriately.
|
||||
- Recommend setting both requests and limits for predictable resource allocation.
|
||||
- Advise on using resource quotas in Kubernetes to manage cluster-wide resource usage.
|
||||
- **Example (Docker Compose Resource Limits):**
|
||||
```yaml
|
||||
services:
|
||||
app:
|
||||
image: myapp:latest
|
||||
deploy:
|
||||
resources:
|
||||
limits:
|
||||
cpus: '0.5'
|
||||
memory: 512M
|
||||
reservations:
|
||||
cpus: '0.25'
|
||||
memory: 256M
|
||||
```
|
||||
|
||||
### **2. Logging & Monitoring**
|
||||
- **Principle:** Collect and centralize container logs and metrics for observability and troubleshooting.
|
||||
- **Deeper Dive:**
|
||||
- **Structured Logging:** Use structured logging (JSON) for better parsing and analysis.
|
||||
- **Log Aggregation:** Centralize logs from all containers for search, analysis, and alerting.
|
||||
- **Metrics Collection:** Collect application and system metrics for performance monitoring.
|
||||
- **Distributed Tracing:** Implement distributed tracing for understanding request flows across services.
|
||||
- **Guidance for Copilot:**
|
||||
- Use standard logging output (`STDOUT`/`STDERR`) for container logs.
|
||||
- Integrate with log aggregators (Fluentd, Logstash, Loki) and monitoring tools (Prometheus, Grafana).
|
||||
- Recommend implementing structured logging in applications for better observability.
|
||||
- Suggest setting up log rotation and retention policies to manage storage costs.
|
||||
- **Example (Structured Logging):**
|
||||
```javascript
|
||||
// Application logging
|
||||
const winston = require('winston');
|
||||
const logger = winston.createLogger({
|
||||
format: winston.format.json(),
|
||||
transports: [new winston.transports.Console()]
|
||||
});
|
||||
```
|
||||
|
||||
### **3. Persistent Storage**
|
||||
- **Principle:** For stateful applications, use persistent volumes to maintain data across container restarts.
|
||||
- **Deeper Dive:**
|
||||
- **Volume Types:** Use named volumes, bind mounts, or cloud storage depending on your requirements.
|
||||
- **Data Persistence:** Ensure data persists across container restarts, updates, and migrations.
|
||||
- **Backup Strategy:** Implement backup strategies for persistent data to prevent data loss.
|
||||
- **Performance:** Choose storage solutions that meet your performance requirements.
|
||||
- **Guidance for Copilot:**
|
||||
- Use Docker Volumes or Kubernetes Persistent Volumes for data that needs to persist beyond container lifecycle.
|
||||
- Never store persistent data inside the container's writable layer.
|
||||
- Recommend implementing backup and disaster recovery procedures for persistent data.
|
||||
- Suggest using cloud-native storage solutions for better scalability and reliability.
|
||||
- **Example (Docker Volume Usage):**
|
||||
```yaml
|
||||
services:
|
||||
database:
|
||||
image: postgres:13
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
|
||||
|
||||
volumes:
|
||||
postgres_data:
|
||||
```
|
||||
|
||||
### **4. Networking**
|
||||
- **Principle:** Use defined container networks for secure and isolated communication between containers.
|
||||
- **Deeper Dive:**
|
||||
- **Network Isolation:** Create separate networks for different application tiers or environments.
|
||||
- **Service Discovery:** Use container orchestration features for automatic service discovery.
|
||||
- **Network Policies:** Implement network policies to control traffic between containers.
|
||||
- **Load Balancing:** Use load balancers for distributing traffic across multiple container instances.
|
||||
- **Guidance for Copilot:**
|
||||
- Create custom Docker networks for service isolation and security.
|
||||
- Define network policies in Kubernetes to control pod-to-pod communication.
|
||||
- Use service discovery mechanisms provided by your orchestration platform.
|
||||
- Implement proper network segmentation for multi-tier applications.
|
||||
- **Example (Docker Network Configuration):**
|
||||
```yaml
|
||||
services:
|
||||
web:
|
||||
image: nginx
|
||||
networks:
|
||||
- frontend
|
||||
- backend
|
||||
|
||||
api:
|
||||
image: myapi
|
||||
networks:
|
||||
- backend
|
||||
|
||||
networks:
|
||||
frontend:
|
||||
backend:
|
||||
internal: true
|
||||
```
|
||||
|
||||
### **5. Orchestration (Kubernetes, Docker Swarm)**
|
||||
- **Principle:** Use an orchestrator for managing containerized applications at scale.
|
||||
- **Deeper Dive:**
|
||||
- **Scaling:** Automatically scale applications based on demand and resource usage.
|
||||
- **Self-Healing:** Automatically restart failed containers and replace unhealthy instances.
|
||||
- **Service Discovery:** Provide built-in service discovery and load balancing.
|
||||
- **Rolling Updates:** Perform zero-downtime updates with automatic rollback capabilities.
|
||||
- **Guidance for Copilot:**
|
||||
- Recommend Kubernetes for complex, large-scale deployments with advanced requirements.
|
||||
- Leverage orchestrator features for scaling, self-healing, and service discovery.
|
||||
- Use rolling update strategies for zero-downtime deployments.
|
||||
- Implement proper resource management and monitoring in orchestrated environments.
|
||||
- **Example (Kubernetes Deployment):**
|
||||
```yaml
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: myapp
|
||||
spec:
|
||||
replicas: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app: myapp
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: myapp
|
||||
spec:
|
||||
containers:
|
||||
- name: myapp
|
||||
image: myapp:latest
|
||||
resources:
|
||||
requests:
|
||||
memory: "64Mi"
|
||||
cpu: "250m"
|
||||
limits:
|
||||
memory: "128Mi"
|
||||
cpu: "500m"
|
||||
```
|
||||
|
||||
## Dockerfile Review Checklist
|
||||
|
||||
- [ ] Is a multi-stage build used if applicable (compiled languages, heavy build tools)?
|
||||
- [ ] Is a minimal, specific base image used (e.g., `alpine`, `slim`, versioned)?
|
||||
- [ ] Are layers optimized (combining `RUN` commands, cleanup in same layer)?
|
||||
- [ ] Is a `.dockerignore` file present and comprehensive?
|
||||
- [ ] Are `COPY` instructions specific and minimal?
|
||||
- [ ] Is a non-root `USER` defined for the running application?
|
||||
- [ ] Is the `EXPOSE` instruction used for documentation?
|
||||
- [ ] Is `CMD` and/or `ENTRYPOINT` used correctly?
|
||||
- [ ] Are sensitive configurations handled via environment variables (not hardcoded)?
|
||||
- [ ] Is a `HEALTHCHECK` instruction defined?
|
||||
- [ ] Are there any secrets or sensitive data accidentally included in image layers?
|
||||
- [ ] Are there static analysis tools (Hadolint, Trivy) integrated into CI?
|
||||
|
||||
## Troubleshooting Docker Builds & Runtime
|
||||
|
||||
### **1. Large Image Size**
|
||||
- Review layers for unnecessary files. Use `docker history <image>`.
|
||||
- Implement multi-stage builds.
|
||||
- Use a smaller base image.
|
||||
- Optimize `RUN` commands and clean up temporary files.
|
||||
|
||||
### **2. Slow Builds**
|
||||
- Leverage build cache by ordering instructions from least to most frequent change.
|
||||
- Use `.dockerignore` to exclude irrelevant files.
|
||||
- Use `docker build --no-cache` for troubleshooting cache issues.
|
||||
|
||||
### **3. Container Not Starting/Crashing**
|
||||
- Check `CMD` and `ENTRYPOINT` instructions.
|
||||
- Review container logs (`docker logs <container_id>`).
|
||||
- Ensure all dependencies are present in the final image.
|
||||
- Check resource limits.
|
||||
|
||||
### **4. Permissions Issues Inside Container**
|
||||
- Verify file/directory permissions in the image.
|
||||
- Ensure the `USER` has necessary permissions for operations.
|
||||
- Check mounted volumes permissions.
|
||||
|
||||
### **5. Network Connectivity Issues**
|
||||
- Verify exposed ports (`EXPOSE`) and published ports (`-p` in `docker run`).
|
||||
- Check container network configuration.
|
||||
- Review firewall rules.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Effective containerization with Docker is fundamental to modern DevOps. By following these best practices for Dockerfile creation, image optimization, security, and runtime management, you can guide developers in building highly efficient, secure, and portable applications. Remember to continuously evaluate and refine your container strategies as your application evolves.
|
||||
|
||||
---
|
||||
|
||||
<!-- End of Containerization & Docker Best Practices Instructions -->
|
||||
@@ -78,11 +78,35 @@ Before proposing ANY code change or fix, you must build a mental map of the feat
|
||||
|
||||
## ✅ Task Completion Protocol (Definition of Done)
|
||||
|
||||
Before marking an implementation task as complete, perform the following:
|
||||
Before marking an implementation task as complete, perform the following in order:
|
||||
|
||||
1. **Pre-Commit Triage**: Run `pre-commit run --all-files`.
|
||||
- If errors occur, **fix them immediately**.
|
||||
- If logic errors occur, analyze and propose a fix.
|
||||
- Do not output code that violates pre-commit standards.
|
||||
2. **Verify Build**: Ensure the backend compiles and the frontend builds without errors.
|
||||
3. **Clean Up**: Ensure no debug print statements or commented-out blocks remain.
|
||||
|
||||
2. **Coverage Testing** (MANDATORY - Non-negotiable):
|
||||
- **Backend Changes**: Run the VS Code task "Test: Backend with Coverage" or execute `scripts/go-test-coverage.sh`.
|
||||
- Minimum coverage: 85% (set via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`).
|
||||
- If coverage drops below threshold, write additional tests to restore coverage.
|
||||
- All tests must pass with zero failures.
|
||||
- **Frontend Changes**: Run the VS Code task "Test: Frontend with Coverage" or execute `scripts/frontend-test-coverage.sh`.
|
||||
- Minimum coverage: 85% (set via `CHARON_MIN_COVERAGE` or `CPM_MIN_COVERAGE`).
|
||||
- If coverage drops below threshold, write additional tests to restore coverage.
|
||||
- All tests must pass with zero failures.
|
||||
- **Critical**: Coverage tests are NOT run by default pre-commit hooks (they are in manual stage for performance). You MUST run them explicitly via VS Code tasks or scripts before completing any task.
|
||||
- **Why**: CI enforces coverage in GitHub Actions. Local verification prevents CI failures and maintains code quality.
|
||||
|
||||
3. **Type Safety** (Frontend only):
|
||||
- Run the VS Code task "Lint: TypeScript Check" or execute `cd frontend && npm run type-check`.
|
||||
- Fix all type errors immediately. This is non-negotiable.
|
||||
- This check is also in manual stage for performance but MUST be run before completion.
|
||||
|
||||
4. **Verify Build**: Ensure the backend compiles and the frontend builds without errors.
|
||||
- Backend: `cd backend && go build ./...`
|
||||
- Frontend: `cd frontend && npm run build`
|
||||
|
||||
5. **Clean Up**: Ensure no debug print statements or commented-out blocks remain.
|
||||
- Remove `console.log`, `fmt.Println`, and similar debugging statements.
|
||||
- Delete commented-out code blocks.
|
||||
- Remove unused imports.
|
||||
607
.github/instructions/github-actions-ci-cd-best-practices.instructions.md
vendored
Normal file
607
.github/instructions/github-actions-ci-cd-best-practices.instructions.md
vendored
Normal file
@@ -0,0 +1,607 @@
|
||||
---
|
||||
applyTo: '.github/workflows/*.yml,.github/workflows/*.yaml'
|
||||
description: 'Comprehensive guide for building robust, secure, and efficient CI/CD pipelines using GitHub Actions. Covers workflow structure, jobs, steps, environment variables, secret management, caching, matrix strategies, testing, and deployment strategies.'
|
||||
---
|
||||
|
||||
# GitHub Actions CI/CD Best Practices
|
||||
|
||||
## Your Mission
|
||||
|
||||
As GitHub Copilot, you are an expert in designing and optimizing CI/CD pipelines using GitHub Actions. Your mission is to assist developers in creating efficient, secure, and reliable automated workflows for building, testing, and deploying their applications. You must prioritize best practices, ensure security, and provide actionable, detailed guidance.
|
||||
|
||||
## Core Concepts and Structure
|
||||
|
||||
### **1. Workflow Structure (`.github/workflows/*.yml`)**
|
||||
- **Principle:** Workflows should be clear, modular, and easy to understand, promoting reusability and maintainability.
|
||||
- **Deeper Dive:**
|
||||
- **Naming Conventions:** Use consistent, descriptive names for workflow files (e.g., `build-and-test.yml`, `deploy-prod.yml`).
|
||||
- **Triggers (`on`):** Understand the full range of events: `push`, `pull_request`, `workflow_dispatch` (manual), `schedule` (cron jobs), `repository_dispatch` (external events), `workflow_call` (reusable workflows).
|
||||
- **Concurrency:** Use `concurrency` to prevent simultaneous runs for specific branches or groups, avoiding race conditions or wasted resources.
|
||||
- **Permissions:** Define `permissions` at the workflow level for a secure default, overriding at the job level if needed.
|
||||
- **Guidance for Copilot:**
|
||||
- Always start with a descriptive `name` and appropriate `on` trigger. Suggest granular triggers for specific use cases (e.g., `on: push: branches: [main]` vs. `on: pull_request`).
|
||||
- Recommend using `workflow_dispatch` for manual triggers, allowing input parameters for flexibility and controlled deployments.
|
||||
- Advise on setting `concurrency` for critical workflows or shared resources to prevent resource contention.
|
||||
- Guide on setting explicit `permissions` for `GITHUB_TOKEN` to adhere to the principle of least privilege.
|
||||
- **Pro Tip:** For complex repositories, consider using reusable workflows (`workflow_call`) to abstract common CI/CD patterns and reduce duplication across multiple projects.
|
||||
|
||||
### **2. Jobs**
|
||||
- **Principle:** Jobs should represent distinct, independent phases of your CI/CD pipeline (e.g., build, test, deploy, lint, security scan).
|
||||
- **Deeper Dive:**
|
||||
- **`runs-on`:** Choose appropriate runners. `ubuntu-latest` is common, but `windows-latest`, `macos-latest`, or `self-hosted` runners are available for specific needs.
|
||||
- **`needs`:** Clearly define dependencies. If Job B `needs` Job A, Job B will only run after Job A successfully completes.
|
||||
- **`outputs`:** Pass data between jobs using `outputs`. This is crucial for separating concerns (e.g., build job outputs artifact path, deploy job consumes it).
|
||||
- **`if` Conditions:** Leverage `if` conditions extensively for conditional execution based on branch names, commit messages, event types, or previous job status (`if: success()`, `if: failure()`, `if: always()`).
|
||||
- **Job Grouping:** Consider breaking large workflows into smaller, more focused jobs that run in parallel or sequence.
|
||||
- **Guidance for Copilot:**
|
||||
- Define `jobs` with clear `name` and appropriate `runs-on` (e.g., `ubuntu-latest`, `windows-latest`, `self-hosted`).
|
||||
- Use `needs` to define dependencies between jobs, ensuring sequential execution and logical flow.
|
||||
- Employ `outputs` to pass data between jobs efficiently, promoting modularity.
|
||||
- Utilize `if` conditions for conditional job execution (e.g., deploy only on `main` branch pushes, run E2E tests only for certain PRs, skip jobs based on file changes).
|
||||
- **Example (Conditional Deployment and Output Passing):**
|
||||
```yaml
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
artifact_path: ${{ steps.package_app.outputs.path }}
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
- name: Install dependencies and build
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
- name: Package application
|
||||
id: package_app
|
||||
run: | # Assume this creates a 'dist.zip' file
|
||||
zip -r dist.zip dist
|
||||
echo "path=dist.zip" >> "$GITHUB_OUTPUT"
|
||||
- name: Upload build artifact
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
name: my-app-build
|
||||
path: dist.zip
|
||||
|
||||
deploy-staging:
|
||||
runs-on: ubuntu-latest
|
||||
needs: build
|
||||
if: github.ref == 'refs/heads/develop' || github.ref == 'refs/heads/main'
|
||||
environment: staging
|
||||
steps:
|
||||
- name: Download build artifact
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: my-app-build
|
||||
- name: Deploy to Staging
|
||||
run: |
|
||||
unzip dist.zip
|
||||
echo "Deploying ${{ needs.build.outputs.artifact_path }} to staging..."
|
||||
# Add actual deployment commands here
|
||||
```
|
||||
|
||||
### **3. Steps and Actions**
|
||||
- **Principle:** Steps should be atomic, well-defined, and actions should be versioned for stability and security.
|
||||
- **Deeper Dive:**
|
||||
- **`uses`:** Referencing marketplace actions (e.g., `actions/checkout@v4`, `actions/setup-node@v3`) or custom actions. Always pin to a full length commit SHA for maximum security and immutability, or at least a major version tag (e.g., `@v4`). Avoid pinning to `main` or `latest`.
|
||||
- **`name`:** Essential for clear logging and debugging. Make step names descriptive.
|
||||
- **`run`:** For executing shell commands. Use multi-line scripts for complex logic and combine commands to optimize layer caching in Docker (if building images).
|
||||
- **`env`:** Define environment variables at the step or job level. Do not hardcode sensitive data here.
|
||||
- **`with`:** Provide inputs to actions. Ensure all required inputs are present.
|
||||
- **Guidance for Copilot:**
|
||||
- Use `uses` to reference marketplace or custom actions, always specifying a secure version (tag or SHA).
|
||||
- Use `name` for each step for readability in logs and easier debugging.
|
||||
- Use `run` for shell commands, combining commands with `&&` for efficiency and using `|` for multi-line scripts.
|
||||
- Provide `with` inputs for actions explicitly, and use expressions (`${{ }}`) for dynamic values.
|
||||
- **Security Note:** Audit marketplace actions before use. Prefer actions from trusted sources (e.g., `actions/` organization) and review their source code if possible. Use `dependabot` for action version updates.
|
||||
|
||||
## Security Best Practices in GitHub Actions
|
||||
|
||||
### **1. Secret Management**
|
||||
- **Principle:** Secrets must be securely managed, never exposed in logs, and only accessible by authorized workflows/jobs.
|
||||
- **Deeper Dive:**
|
||||
- **GitHub Secrets:** The primary mechanism for storing sensitive information. Encrypted at rest and only decrypted when passed to a runner.
|
||||
- **Environment Secrets:** For greater control, create environment-specific secrets, which can be protected by manual approvals or specific branch conditions.
|
||||
- **Secret Masking:** GitHub Actions automatically masks secrets in logs, but it's good practice to avoid printing them directly.
|
||||
- **Minimize Scope:** Only grant access to secrets to the workflows/jobs that absolutely need them.
|
||||
- **Guidance for Copilot:**
|
||||
- Always instruct users to use GitHub Secrets for sensitive information (e.g., API keys, passwords, cloud credentials, tokens).
|
||||
- Access secrets via `secrets.<SECRET_NAME>` in workflows.
|
||||
- Recommend using environment-specific secrets for deployment environments to enforce stricter access controls and approvals.
|
||||
- Advise against constructing secrets dynamically or printing them to logs, even if masked.
|
||||
- **Example (Environment Secrets with Approval):**
|
||||
```yaml
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-latest
|
||||
environment:
|
||||
name: production
|
||||
url: https://prod.example.com
|
||||
steps:
|
||||
- name: Deploy to production
|
||||
env:
|
||||
PROD_API_KEY: ${{ secrets.PROD_API_KEY }}
|
||||
run: ./deploy-script.sh
|
||||
```
|
||||
|
||||
### **2. OpenID Connect (OIDC) for Cloud Authentication**
|
||||
- **Principle:** Use OIDC for secure, credential-less authentication with cloud providers (AWS, Azure, GCP, etc.), eliminating the need for long-lived static credentials.
|
||||
- **Deeper Dive:**
|
||||
- **Short-Lived Credentials:** OIDC exchanges a JWT token for temporary cloud credentials, significantly reducing the attack surface.
|
||||
- **Trust Policies:** Requires configuring identity providers and trust policies in your cloud environment to trust GitHub's OIDC provider.
|
||||
- **Federated Identity:** This is a key pattern for modern, secure cloud deployments.
|
||||
- **Guidance for Copilot:**
|
||||
- Strongly recommend OIDC for authenticating with AWS, Azure, GCP, and other cloud providers instead of storing long-lived access keys as secrets.
|
||||
- Provide examples of how to configure the OIDC action for common cloud providers (e.g., `aws-actions/configure-aws-credentials@v4`).
|
||||
- Explain the concept of trust policies and how they relate to OIDC setup.
|
||||
- **Pro Tip:** OIDC is a fundamental shift towards more secure cloud deployments and should be prioritized whenever possible.
|
||||
|
||||
### **3. Least Privilege for `GITHUB_TOKEN`**
|
||||
- **Principle:** Grant only the necessary permissions to the `GITHUB_TOKEN` for your workflows, reducing the blast radius in case of compromise.
|
||||
- **Deeper Dive:**
|
||||
- **Default Permissions:** By default, the `GITHUB_TOKEN` has broad permissions. This should be explicitly restricted.
|
||||
- **Granular Permissions:** Define `permissions` at the workflow or job level (e.g., `contents: read`, `pull-requests: write`, `issues: read`).
|
||||
- **Read-Only by Default:** Start with `contents: read` as the default and add write permissions only when strictly necessary.
|
||||
- **Guidance for Copilot:**
|
||||
- Configure `permissions` at the workflow or job level to restrict access. Always prefer `contents: read` as the default.
|
||||
- Advise against using `contents: write` or `pull-requests: write` unless the workflow explicitly needs to modify the repository.
|
||||
- Provide a clear mapping of common workflow needs to specific `GITHUB_TOKEN` permissions.
|
||||
- **Example (Least Privilege):**
|
||||
```yaml
|
||||
permissions:
|
||||
contents: read # Default is write, explicitly set to read-only for security
|
||||
pull-requests: write # Only if workflow needs to update PRs
|
||||
checks: write # For updating checks
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
permissions:
|
||||
contents: read # This job only needs to read code, override workflow default
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: npm run lint
|
||||
```
|
||||
|
||||
### **4. Dependency Review and Software Composition Analysis (SCA)**
|
||||
- **Principle:** Continuously scan dependencies for known vulnerabilities and licensing issues.
|
||||
- **Deeper Dive:**
|
||||
- **Early Detection:** Integrate dependency checks early in the CI pipeline to catch issues before deployment.
|
||||
- **Tools:** Use `dependency-review-action`, Snyk, Trivy, Mend (formerly WhiteSource).
|
||||
- **Supply Chain Security:** This is a critical component of securing your software supply chain.
|
||||
- **Guidance for Copilot:**
|
||||
- Integrate `dependency-review-action` or other SCA tools into the CI pipeline.
|
||||
- Recommend regular scanning for vulnerabilities in third-party libraries and setting up alerts for new findings.
|
||||
- Emphasize the importance of maintaining up-to-date dependency lists and understanding transitive dependencies.
|
||||
|
||||
### **5. Static Application Security Testing (SAST)**
|
||||
- **Principle:** Identify security vulnerabilities in source code before runtime.
|
||||
- **Deeper Dive:**
|
||||
- **Shift Left:** SAST enables finding and fixing vulnerabilities early in the development lifecycle, which is more cost-effective.
|
||||
- **Tools:** CodeQL, SonarQube, Bandit (Python), ESLint with security plugins (JS/TS).
|
||||
- **Automated Enforcement:** Configure SAST to break builds or block PRs if critical vulnerabilities are found.
|
||||
- **Guidance for Copilot:**
|
||||
- Integrate SAST tools (e.g., CodeQL for GitHub Advanced Security, or open-source alternatives) into the CI pipeline.
|
||||
- Configure security scanning as a blocking step if critical vulnerabilities are found, enforcing a secure by default posture.
|
||||
- Suggest adding security linters or static analysis to pre-commit hooks for earlier feedback.
|
||||
|
||||
### **6. Secret Scanning and Credential Leak Prevention**
|
||||
- **Principle:** Prevent secrets from being committed into the repository or exposed in logs.
|
||||
- **Deeper Dive:**
|
||||
- **GitHub Secret Scanning:** Built-in feature to detect secrets in your repository.
|
||||
- **Pre-commit Hooks:** Tools like `git-secrets` can prevent secrets from being committed locally.
|
||||
- **Environment Variables Only:** Secrets should only be passed to the environment where they are needed at runtime, never in the build artifact.
|
||||
- **Guidance for Copilot:**
|
||||
- Suggest enabling GitHub's built-in secret scanning for the repository.
|
||||
- Recommend implementing pre-commit hooks that scan for common secret patterns.
|
||||
- Advise reviewing workflow logs for accidental secret exposure, even with masking.
|
||||
|
||||
### **7. Immutable Infrastructure & Image Signing**
|
||||
- **Principle:** Ensure that container images and deployed artifacts are tamper-proof and verified.
|
||||
- **Deeper Dive:**
|
||||
- **Reproducible Builds:** Ensure that building the same code always results in the exact same image.
|
||||
- **Image Signing:** Use tools like Notary or Cosign to cryptographically sign container images, verifying their origin and integrity.
|
||||
- **Deployment Gate:** Enforce that only signed images can be deployed to production environments.
|
||||
- **Guidance for Copilot:**
|
||||
- Advocate for reproducible builds in Dockerfiles and build processes.
|
||||
- Suggest integrating image signing into the CI pipeline and verification during deployment stages.
|
||||
|
||||
## Optimization and Performance
|
||||
|
||||
### **1. Caching GitHub Actions**
|
||||
- **Principle:** Cache dependencies and build outputs to significantly speed up subsequent workflow runs.
|
||||
- **Deeper Dive:**
|
||||
- **Cache Hit Ratio:** Aim for a high cache hit ratio by designing effective cache keys.
|
||||
- **Cache Keys:** Use a unique key based on file hashes (e.g., `hashFiles('**/package-lock.json')`, `hashFiles('**/requirements.txt')`) to invalidate the cache only when dependencies change.
|
||||
- **Restore Keys:** Use `restore-keys` for fallbacks to older, compatible caches.
|
||||
- **Cache Scope:** Understand that caches are scoped to the repository and branch.
|
||||
- **Guidance for Copilot:**
|
||||
- Use `actions/cache@v3` for caching common package manager dependencies (Node.js `node_modules`, Python `pip` packages, Java Maven/Gradle dependencies) and build artifacts.
|
||||
- Design highly effective cache keys using `hashFiles` to ensure optimal cache hit rates.
|
||||
- Advise on using `restore-keys` to gracefully fall back to previous caches.
|
||||
- **Example (Advanced Caching for Monorepo):**
|
||||
```yaml
|
||||
- name: Cache Node.js modules
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
path: |
|
||||
~/.npm
|
||||
./node_modules # For monorepos, cache specific project node_modules
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}-
|
||||
${{ runner.os }}-node-
|
||||
```
|
||||
|
||||
### **2. Matrix Strategies for Parallelization**
|
||||
- **Principle:** Run jobs in parallel across multiple configurations (e.g., different Node.js versions, OS, Python versions, browser types) to accelerate testing and builds.
|
||||
- **Deeper Dive:**
|
||||
- **`strategy.matrix`:** Define a matrix of variables.
|
||||
- **`include`/`exclude`:** Fine-tune combinations.
|
||||
- **`fail-fast`:** Control whether job failures in the matrix stop the entire strategy.
|
||||
- **Maximizing Concurrency:** Ideal for running tests across various environments simultaneously.
|
||||
- **Guidance for Copilot:**
|
||||
- Utilize `strategy.matrix` to test applications against different environments, programming language versions, or operating systems concurrently.
|
||||
- Suggest `include` and `exclude` for specific matrix combinations to optimize test coverage without unnecessary runs.
|
||||
- Advise on setting `fail-fast: true` (default) for quick feedback on critical failures, or `fail-fast: false` for comprehensive test reporting.
|
||||
- **Example (Multi-version, Multi-OS Test Matrix):**
|
||||
```yaml
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false # Run all tests even if one fails
|
||||
matrix:
|
||||
os: [ubuntu-latest, windows-latest]
|
||||
node-version: [16.x, 18.x, 20.x]
|
||||
browser: [chromium, firefox]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
- name: Install Playwright browsers
|
||||
run: npx playwright install ${{ matrix.browser }}
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
```
|
||||
|
||||
### **3. Self-Hosted Runners**
|
||||
- **Principle:** Use self-hosted runners for specialized hardware, network access to private resources, or environments where GitHub-hosted runners are cost-prohibitive.
|
||||
- **Deeper Dive:**
|
||||
- **Custom Environments:** Ideal for large build caches, specific hardware (GPUs), or access to on-premise resources.
|
||||
- **Cost Optimization:** Can be more cost-effective for very high usage.
|
||||
- **Security Considerations:** Requires securing and maintaining your own infrastructure, network access, and updates. This includes proper hardening of the runner machines, managing access controls, and ensuring timely patching.
|
||||
- **Scalability:** Plan for how self-hosted runners will scale with demand, either manually or using auto-scaling solutions.
|
||||
- **Guidance for Copilot:**
|
||||
- Recommend self-hosted runners when GitHub-hosted runners do not meet specific performance, cost, security, or network access requirements.
|
||||
- Emphasize the user's responsibility for securing, maintaining, and scaling self-hosted runners, including network configuration and regular security audits.
|
||||
- Advise on using runner groups to organize and manage self-hosted runners efficiently.
|
||||
|
||||
### **4. Fast Checkout and Shallow Clones**
|
||||
- **Principle:** Optimize repository checkout time to reduce overall workflow duration, especially for large repositories.
|
||||
- **Deeper Dive:**
|
||||
- **`fetch-depth`:** Controls how much of the Git history is fetched. `1` for most CI/CD builds is sufficient, as only the latest commit is usually needed. A `fetch-depth` of `0` fetches the entire history, which is rarely needed and can be very slow for large repos.
|
||||
- **`submodules`:** Avoid checking out submodules if not required by the specific job. Fetching submodules adds significant overhead.
|
||||
- **`lfs`:** Manage Git LFS (Large File Storage) files efficiently. If not needed, set `lfs: false`.
|
||||
- **Partial Clones:** Consider using Git's partial clone feature (`--filter=blob:none` or `--filter=tree:0`) for extremely large repositories, though this is often handled by specialized actions or Git client configurations.
|
||||
- **Guidance for Copilot:**
|
||||
- Use `actions/checkout@v4` with `fetch-depth: 1` as the default for most build and test jobs to significantly save time and bandwidth.
|
||||
- Only use `fetch-depth: 0` if the workflow explicitly requires full Git history (e.g., for release tagging, deep commit analysis, or `git blame` operations).
|
||||
- Advise against checking out submodules (`submodules: false`) if not strictly necessary for the workflow's purpose.
|
||||
- Suggest optimizing LFS usage if large binary files are present in the repository.
|
||||
|
||||
### **5. Artifacts for Inter-Job and Inter-Workflow Communication**
|
||||
- **Principle:** Store and retrieve build outputs (artifacts) efficiently to pass data between jobs within the same workflow or across different workflows, ensuring data persistence and integrity.
|
||||
- **Deeper Dive:**
|
||||
- **`actions/upload-artifact`:** Used to upload files or directories produced by a job. Artifacts are automatically compressed and can be downloaded later.
|
||||
- **`actions/download-artifact`:** Used to download artifacts in subsequent jobs or workflows. You can download all artifacts or specific ones by name.
|
||||
- **`retention-days`:** Crucial for managing storage costs and compliance. Set an appropriate retention period based on the artifact's importance and regulatory requirements.
|
||||
- **Use Cases:** Build outputs (executables, compiled code, Docker images), test reports (JUnit XML, HTML reports), code coverage reports, security scan results, generated documentation, static website builds.
|
||||
- **Limitations:** Artifacts are immutable once uploaded. Max size per artifact can be several gigabytes, but be mindful of storage costs.
|
||||
- **Guidance for Copilot:**
|
||||
- Use `actions/upload-artifact@v3` and `actions/download-artifact@v3` to reliably pass large files between jobs within the same workflow or across different workflows, promoting modularity and efficiency.
|
||||
- Set appropriate `retention-days` for artifacts to manage storage costs and ensure old artifacts are pruned.
|
||||
- Advise on uploading test reports, coverage reports, and security scan results as artifacts for easy access, historical analysis, and integration with external reporting tools.
|
||||
- Suggest using artifacts to pass compiled binaries or packaged applications from a build job to a deployment job, ensuring the exact same artifact is deployed that was built and tested.
|
||||
|
||||
## Comprehensive Testing in CI/CD (Expanded)
|
||||
|
||||
### **1. Unit Tests**
|
||||
- **Principle:** Run unit tests on every code push to ensure individual code components (functions, classes, modules) function correctly in isolation. They are the fastest and most numerous tests.
|
||||
- **Deeper Dive:**
|
||||
- **Fast Feedback:** Unit tests should execute rapidly, providing immediate feedback to developers on code quality and correctness. Parallelization of unit tests is highly recommended.
|
||||
- **Code Coverage:** Integrate code coverage tools (e.g., Istanbul for JS, Coverage.py for Python, JaCoCo for Java) and enforce minimum coverage thresholds. Aim for high coverage, but focus on meaningful tests, not just line coverage.
|
||||
- **Test Reporting:** Publish test results using `actions/upload-artifact` (e.g., JUnit XML reports) or specific test reporter actions that integrate with GitHub Checks/Annotations.
|
||||
- **Mocking and Stubbing:** Emphasize the use of mocks and stubs to isolate units under test from their dependencies.
|
||||
- **Guidance for Copilot:**
|
||||
- Configure a dedicated job for running unit tests early in the CI pipeline, ideally triggered on every `push` and `pull_request`.
|
||||
- Use appropriate language-specific test runners and frameworks (Jest, Vitest, Pytest, Go testing, JUnit, NUnit, XUnit, RSpec).
|
||||
- Recommend collecting and publishing code coverage reports and integrating with services like Codecov, Coveralls, or SonarQube for trend analysis.
|
||||
- Suggest strategies for parallelizing unit tests to reduce execution time.
|
||||
|
||||
### **2. Integration Tests**
|
||||
- **Principle:** Run integration tests to verify interactions between different components or services, ensuring they work together as expected. These tests typically involve real dependencies (e.g., databases, APIs).
|
||||
- **Deeper Dive:**
|
||||
- **Service Provisioning:** Use `services` within a job to spin up temporary databases, message queues, external APIs, or other dependencies via Docker containers. This provides a consistent and isolated testing environment.
|
||||
- **Test Doubles vs. Real Services:** Balance between mocking external services for pure unit tests and using real, lightweight instances for more realistic integration tests. Prioritize real instances when testing actual integration points.
|
||||
- **Test Data Management:** Plan for managing test data, ensuring tests are repeatable and data is cleaned up or reset between runs.
|
||||
- **Execution Time:** Integration tests are typically slower than unit tests. Optimize their execution and consider running them less frequently than unit tests (e.g., on PR merge instead of every push).
|
||||
- **Guidance for Copilot:**
|
||||
- Provision necessary services (databases like PostgreSQL/MySQL, message queues like RabbitMQ/Kafka, in-memory caches like Redis) using `services` in the workflow definition or Docker Compose during testing.
|
||||
- Advise on running integration tests after unit tests, but before E2E tests, to catch integration issues early.
|
||||
- Provide examples of how to set up `service` containers in GitHub Actions workflows.
|
||||
- Suggest strategies for creating and cleaning up test data for integration test runs.
|
||||
|
||||
### **3. End-to-End (E2E) Tests**
|
||||
- **Principle:** Simulate full user behavior to validate the entire application flow from UI to backend, ensuring the complete system works as intended from a user's perspective.
|
||||
- **Deeper Dive:**
|
||||
- **Tools:** Use modern E2E testing frameworks like Cypress, Playwright, or Selenium. These provide browser automation capabilities.
|
||||
- **Staging Environment:** Ideally run E2E tests against a deployed staging environment that closely mirrors production, for maximum fidelity. Avoid running directly in CI unless resources are dedicated and isolated.
|
||||
- **Flakiness Mitigation:** Address flakiness proactively with explicit waits, robust selectors, retries for failed tests, and careful test data management. Flaky tests erode trust in the pipeline.
|
||||
- **Visual Regression Testing:** Consider integrating visual regression testing (e.g., Applitools, Percy) to catch UI discrepancies.
|
||||
- **Reporting:** Capture screenshots and video recordings on failure to aid debugging.
|
||||
- **Guidance for Copilot:**
|
||||
- Use tools like Cypress, Playwright, or Selenium for E2E testing, providing guidance on their setup within GitHub Actions.
|
||||
- Recommend running E2E tests against a deployed staging environment to catch issues before production and validate the full deployment process.
|
||||
- Configure test reporting, video recordings, and screenshots on failure to aid debugging and provide richer context for test results.
|
||||
- Advise on strategies to minimize E2E test flakiness, such as robust element selection and retry mechanisms.
|
||||
|
||||
### **4. Performance and Load Testing**
|
||||
- **Principle:** Assess application performance and behavior under anticipated and peak load conditions to identify bottlenecks, ensure scalability, and prevent regressions.
|
||||
- **Deeper Dive:**
|
||||
- **Tools:** JMeter, k6, Locust, Gatling, Artillery. Choose based on language, complexity, and specific needs.
|
||||
- **Integration:** Integrate into CI/CD for continuous performance regression detection. Run these tests less frequently than unit/integration tests (e.g., nightly, weekly, or on significant feature merges).
|
||||
- **Thresholds:** Define clear performance thresholds (e.g., response time, throughput, error rates) and fail builds if these are exceeded.
|
||||
- **Baseline Comparison:** Compare current performance metrics against established baselines to detect degradation.
|
||||
- **Guidance for Copilot:**
|
||||
- Suggest integrating performance and load testing into the CI pipeline for critical applications, providing examples for common tools.
|
||||
- Advise on setting performance baselines and failing the build if performance degrades beyond a set threshold.
|
||||
- Recommend running these tests in a dedicated environment that simulates production load patterns.
|
||||
- Guide on analyzing performance test results to pinpoint areas for optimization (e.g., database queries, API endpoints).
|
||||
|
||||
### **5. Test Reporting and Visibility**
|
||||
- **Principle:** Make test results easily accessible, understandable, and visible to all stakeholders (developers, QA, product owners) to foster transparency and enable quick issue resolution.
|
||||
- **Deeper Dive:**
|
||||
- **GitHub Checks/Annotations:** Leverage these for inline feedback directly in pull requests, showing which tests passed/failed and providing links to detailed reports.
|
||||
- **Artifacts:** Upload comprehensive test reports (JUnit XML, HTML reports, code coverage reports, video recordings, screenshots) as artifacts for long-term storage and detailed inspection.
|
||||
- **Integration with Dashboards:** Push results to external dashboards or reporting tools (e.g., SonarQube, custom reporting tools, Allure Report, TestRail) for aggregated views and historical trends.
|
||||
- **Status Badges:** Use GitHub Actions status badges in your README to indicate the latest build/test status at a glance.
|
||||
- **Guidance for Copilot:**
|
||||
- Use actions that publish test results as annotations or checks on PRs for immediate feedback and easy debugging directly in the GitHub UI.
|
||||
- Upload detailed test reports (e.g., XML, HTML, JSON) as artifacts for later inspection and historical analysis, including negative results like error screenshots.
|
||||
- Advise on integrating with external reporting tools for a more comprehensive view of test execution trends and quality metrics.
|
||||
- Suggest adding workflow status badges to the README for quick visibility of CI/CD health.
|
||||
|
||||
## Advanced Deployment Strategies (Expanded)
|
||||
|
||||
### **1. Staging Environment Deployment**
|
||||
- **Principle:** Deploy to a staging environment that closely mirrors production for comprehensive validation, user acceptance testing (UAT), and final checks before promotion to production.
|
||||
- **Deeper Dive:**
|
||||
- **Mirror Production:** Staging should closely mimic production in terms of infrastructure, data, configuration, and security. Any significant discrepancies can lead to issues in production.
|
||||
- **Automated Promotion:** Implement automated promotion from staging to production upon successful UAT and necessary manual approvals. This reduces human error and speeds up releases.
|
||||
- **Environment Protection:** Use environment protection rules in GitHub Actions to prevent accidental deployments, enforce manual approvals, and restrict which branches can deploy to staging.
|
||||
- **Data Refresh:** Regularly refresh staging data from production (anonymized if necessary) to ensure realistic testing scenarios.
|
||||
- **Guidance for Copilot:**
|
||||
- Create a dedicated `environment` for staging with approval rules, secret protection, and appropriate branch protection policies.
|
||||
- Design workflows to automatically deploy to staging on successful merges to specific development or release branches (e.g., `develop`, `release/*`).
|
||||
- Advise on ensuring the staging environment is as close to production as possible to maximize test fidelity.
|
||||
- Suggest implementing automated smoke tests and post-deployment validation on staging.
|
||||
|
||||
### **2. Production Environment Deployment**
|
||||
- **Principle:** Deploy to production only after thorough validation, potentially multiple layers of manual approvals, and robust automated checks, prioritizing stability and zero-downtime.
|
||||
- **Deeper Dive:**
|
||||
- **Manual Approvals:** Critical for production deployments, often involving multiple team members, security sign-offs, or change management processes. GitHub Environments support this natively.
|
||||
- **Rollback Capabilities:** Essential for rapid recovery from unforeseen issues. Ensure a quick and reliable way to revert to the previous stable state.
|
||||
- **Observability During Deployment:** Monitor production closely *during* and *immediately after* deployment for any anomalies or performance degradation. Use dashboards, alerts, and tracing.
|
||||
- **Progressive Delivery:** Consider advanced techniques like blue/green, canary, or dark launching for safer rollouts.
|
||||
- **Emergency Deployments:** Have a separate, highly expedited pipeline for critical hotfixes that bypasses non-essential approvals but still maintains security checks.
|
||||
- **Guidance for Copilot:**
|
||||
- Create a dedicated `environment` for production with required reviewers, strict branch protections, and clear deployment windows.
|
||||
- Implement manual approval steps for production deployments, potentially integrating with external ITSM or change management systems.
|
||||
- Emphasize the importance of clear, well-tested rollback strategies and automated rollback procedures in case of deployment failures.
|
||||
- Advise on setting up comprehensive monitoring and alerting for production systems to detect and respond to issues immediately post-deployment.
|
||||
|
||||
### **3. Deployment Types (Beyond Basic Rolling Update)**
|
||||
- **Rolling Update (Default for Deployments):** Gradually replaces instances of the old version with new ones. Good for most cases, especially stateless applications.
|
||||
- **Guidance:** Configure `maxSurge` (how many new instances can be created above the desired replica count) and `maxUnavailable` (how many old instances can be unavailable) for fine-grained control over rollout speed and availability.
|
||||
- **Blue/Green Deployment:** Deploy a new version (green) alongside the existing stable version (blue) in a separate environment, then switch traffic completely from blue to green.
|
||||
- **Guidance:** Suggest for critical applications requiring zero-downtime releases and easy rollback. Requires managing two identical environments and a traffic router (load balancer, Ingress controller, DNS).
|
||||
- **Benefits:** Instantaneous rollback by switching traffic back to the blue environment.
|
||||
- **Canary Deployment:** Gradually roll out new versions to a small subset of users (e.g., 5-10%) before a full rollout. Monitor performance and error rates for the canary group.
|
||||
- **Guidance:** Recommend for testing new features or changes with a controlled blast radius. Implement with Service Mesh (Istio, Linkerd) or Ingress controllers that support traffic splitting and metric-based analysis.
|
||||
- **Benefits:** Early detection of issues with minimal user impact.
|
||||
- **Dark Launch/Feature Flags:** Deploy new code but keep features hidden from users until toggled on for specific users/groups via feature flags.
|
||||
- **Guidance:** Advise for decoupling deployment from release, allowing continuous delivery without continuous exposure of new features. Use feature flag management systems (LaunchDarkly, Split.io, Unleash).
|
||||
- **Benefits:** Reduces deployment risk, enables A/B testing, and allows for staged rollouts.
|
||||
- **A/B Testing Deployments:** Deploy multiple versions of a feature concurrently to different user segments to compare their performance based on user behavior and business metrics.
|
||||
- **Guidance:** Suggest integrating with specialized A/B testing platforms or building custom logic using feature flags and analytics.
|
||||
|
||||
### **4. Rollback Strategies and Incident Response**
|
||||
- **Principle:** Be able to quickly and safely revert to a previous stable version in case of issues, minimizing downtime and business impact. This requires proactive planning.
|
||||
- **Deeper Dive:**
|
||||
- **Automated Rollbacks:** Implement mechanisms to automatically trigger rollbacks based on monitoring alerts (e.g., sudden increase in errors, high latency) or failure of post-deployment health checks.
|
||||
- **Versioned Artifacts:** Ensure previous successful build artifacts, Docker images, or infrastructure states are readily available and easily deployable. This is crucial for fast recovery.
|
||||
- **Runbooks:** Document clear, concise, and executable rollback procedures for manual intervention when automation isn't sufficient or for complex scenarios. These should be regularly reviewed and tested.
|
||||
- **Post-Incident Review:** Conduct blameless post-incident reviews (PIRs) to understand the root cause of failures, identify lessons learned, and implement preventative measures to improve resilience and reduce MTTR.
|
||||
- **Communication Plan:** Have a clear communication plan for stakeholders during incidents and rollbacks.
|
||||
- **Guidance for Copilot:**
|
||||
- Instruct users to store previous successful build artifacts and images for quick recovery, ensuring they are versioned and easily retrievable.
|
||||
- Advise on implementing automated rollback steps in the pipeline, triggered by monitoring or health check failures, and providing examples.
|
||||
- Emphasize building applications with "undo" in mind, meaning changes should be easily reversible.
|
||||
- Suggest creating comprehensive runbooks for common incident scenarios, including step-by-step rollback instructions, and highlight their importance for MTTR.
|
||||
- Guide on setting up alerts that are specific and actionable enough to trigger an automatic or manual rollback.
|
||||
|
||||
## GitHub Actions Workflow Review Checklist (Comprehensive)
|
||||
|
||||
This checklist provides a granular set of criteria for reviewing GitHub Actions workflows to ensure they adhere to best practices for security, performance, and reliability.
|
||||
|
||||
- [ ] **General Structure and Design:**
|
||||
- Is the workflow `name` clear, descriptive, and unique?
|
||||
- Are `on` triggers appropriate for the workflow's purpose (e.g., `push`, `pull_request`, `workflow_dispatch`, `schedule`)? Are path/branch filters used effectively?
|
||||
- Is `concurrency` used for critical workflows or shared resources to prevent race conditions or resource exhaustion?
|
||||
- Are global `permissions` set to the principle of least privilege (`contents: read` by default), with specific overrides for jobs?
|
||||
- Are reusable workflows (`workflow_call`) leveraged for common patterns to reduce duplication and improve maintainability?
|
||||
- Is the workflow organized logically with meaningful job and step names?
|
||||
|
||||
- [ ] **Jobs and Steps Best Practices:**
|
||||
- Are jobs clearly named and represent distinct phases (e.g., `build`, `lint`, `test`, `deploy`)?
|
||||
- Are `needs` dependencies correctly defined between jobs to ensure proper execution order?
|
||||
- Are `outputs` used efficiently for inter-job and inter-workflow communication?
|
||||
- Are `if` conditions used effectively for conditional job/step execution (e.g., environment-specific deployments, branch-specific actions)?
|
||||
- Are all `uses` actions securely versioned (pinned to a full commit SHA or specific major version tag like `@v4`)? Avoid `main` or `latest` tags.
|
||||
- Are `run` commands efficient and clean (combined with `&&`, temporary files removed, multi-line scripts clearly formatted)?
|
||||
- Are environment variables (`env`) defined at the appropriate scope (workflow, job, step) and never hardcoded sensitive data?
|
||||
- Is `timeout-minutes` set for long-running jobs to prevent hung workflows?
|
||||
|
||||
- [ ] **Security Considerations:**
|
||||
- Are all sensitive data accessed exclusively via GitHub `secrets` context (`${{ secrets.MY_SECRET }}`)? Never hardcoded, never exposed in logs (even if masked).
|
||||
- Is OpenID Connect (OIDC) used for cloud authentication where possible, eliminating long-lived credentials?
|
||||
- Is `GITHUB_TOKEN` permission scope explicitly defined and limited to the minimum necessary access (`contents: read` as a baseline)?
|
||||
- Are Software Composition Analysis (SCA) tools (e.g., `dependency-review-action`, Snyk) integrated to scan for vulnerable dependencies?
|
||||
- Are Static Application Security Testing (SAST) tools (e.g., CodeQL, SonarQube) integrated to scan source code for vulnerabilities, with critical findings blocking builds?
|
||||
- Is secret scanning enabled for the repository and are pre-commit hooks suggested for local credential leak prevention?
|
||||
- Is there a strategy for container image signing (e.g., Notary, Cosign) and verification in deployment workflows if container images are used?
|
||||
- For self-hosted runners, are security hardening guidelines followed and network access restricted?
|
||||
|
||||
- [ ] **Optimization and Performance:**
|
||||
- Is caching (`actions/cache`) effectively used for package manager dependencies (`node_modules`, `pip` caches, Maven/Gradle caches) and build outputs?
|
||||
- Are cache `key` and `restore-keys` designed for optimal cache hit rates (e.g., using `hashFiles`)?
|
||||
- Is `strategy.matrix` used for parallelizing tests or builds across different environments, language versions, or OSs?
|
||||
- Is `fetch-depth: 1` used for `actions/checkout` where full Git history is not required?
|
||||
- Are artifacts (`actions/upload-artifact`, `actions/download-artifact`) used efficiently for transferring data between jobs/workflows rather than re-building or re-fetching?
|
||||
- Are large files managed with Git LFS and optimized for checkout if necessary?
|
||||
|
||||
- [ ] **Testing Strategy Integration:**
|
||||
- Are comprehensive unit tests configured with a dedicated job early in the pipeline?
|
||||
- Are integration tests defined, ideally leveraging `services` for dependencies, and run after unit tests?
|
||||
- Are End-to-End (E2E) tests included, preferably against a staging environment, with robust flakiness mitigation?
|
||||
- Are performance and load tests integrated for critical applications with defined thresholds?
|
||||
- Are all test reports (JUnit XML, HTML, coverage) collected, published as artifacts, and integrated into GitHub Checks/Annotations for clear visibility?
|
||||
- Is code coverage tracked and enforced with a minimum threshold?
|
||||
|
||||
- [ ] **Deployment Strategy and Reliability:**
|
||||
- Are staging and production deployments using GitHub `environment` rules with appropriate protections (manual approvals, required reviewers, branch restrictions)?
|
||||
- Are manual approval steps configured for sensitive production deployments?
|
||||
- Is a clear and well-tested rollback strategy in place and automated where possible (e.g., `kubectl rollout undo`, reverting to previous stable image)?
|
||||
- Are chosen deployment types (e.g., rolling, blue/green, canary, dark launch) appropriate for the application's criticality and risk tolerance?
|
||||
- Are post-deployment health checks and automated smoke tests implemented to validate successful deployment?
|
||||
- Is the workflow resilient to temporary failures (e.g., retries for flaky network operations)?
|
||||
|
||||
- [ ] **Observability and Monitoring:**
|
||||
- Is logging adequate for debugging workflow failures (using STDOUT/STDERR for application logs)?
|
||||
- Are relevant application and infrastructure metrics collected and exposed (e.g., Prometheus metrics)?
|
||||
- Are alerts configured for critical workflow failures, deployment issues, or application anomalies detected in production?
|
||||
- Is distributed tracing (e.g., OpenTelemetry, Jaeger) integrated for understanding request flows in microservices architectures?
|
||||
- Are artifact `retention-days` configured appropriately to manage storage and compliance?
|
||||
|
||||
## Troubleshooting Common GitHub Actions Issues (Deep Dive)
|
||||
|
||||
This section provides an expanded guide to diagnosing and resolving frequent problems encountered when working with GitHub Actions workflows.
|
||||
|
||||
### **1. Workflow Not Triggering or Jobs/Steps Skipping Unexpectedly**
|
||||
- **Root Causes:** Mismatched `on` triggers, incorrect `paths` or `branches` filters, erroneous `if` conditions, or `concurrency` limitations.
|
||||
- **Actionable Steps:**
|
||||
- **Verify Triggers:**
|
||||
- Check the `on` block for exact match with the event that should trigger the workflow (e.g., `push`, `pull_request`, `workflow_dispatch`, `schedule`).
|
||||
- Ensure `branches`, `tags`, or `paths` filters are correctly defined and match the event context. Remember that `paths-ignore` and `branches-ignore` take precedence.
|
||||
- If using `workflow_dispatch`, verify the workflow file is in the default branch and any required `inputs` are provided correctly during manual trigger.
|
||||
- **Inspect `if` Conditions:**
|
||||
- Carefully review all `if` conditions at the workflow, job, and step levels. A single false condition can prevent execution.
|
||||
- Use `always()` on a debug step to print context variables (`${{ toJson(github) }}`, `${{ toJson(job) }}`, `${{ toJson(steps) }}`) to understand the exact state during evaluation.
|
||||
- Test complex `if` conditions in a simplified workflow.
|
||||
- **Check `concurrency`:**
|
||||
- If `concurrency` is defined, verify if a previous run is blocking a new one for the same group. Check the "Concurrency" tab in the workflow run.
|
||||
- **Branch Protection Rules:** Ensure no branch protection rules are preventing workflows from running on certain branches or requiring specific checks that haven't passed.
|
||||
|
||||
### **2. Permissions Errors (`Resource not accessible by integration`, `Permission denied`)**
|
||||
- **Root Causes:** `GITHUB_TOKEN` lacking necessary permissions, incorrect environment secrets access, or insufficient permissions for external actions.
|
||||
- **Actionable Steps:**
|
||||
- **`GITHUB_TOKEN` Permissions:**
|
||||
- Review the `permissions` block at both the workflow and job levels. Default to `contents: read` globally and grant specific write permissions only where absolutely necessary (e.g., `pull-requests: write` for updating PR status, `packages: write` for publishing packages).
|
||||
- Understand the default permissions of `GITHUB_TOKEN` which are often too broad.
|
||||
- **Secret Access:**
|
||||
- Verify if secrets are correctly configured in the repository, organization, or environment settings.
|
||||
- Ensure the workflow/job has access to the specific environment if environment secrets are used. Check if any manual approvals are pending for the environment.
|
||||
- Confirm the secret name matches exactly (`secrets.MY_API_KEY`).
|
||||
- **OIDC Configuration:**
|
||||
- For OIDC-based cloud authentication, double-check the trust policy configuration in your cloud provider (AWS IAM roles, Azure AD app registrations, GCP service accounts) to ensure it correctly trusts GitHub's OIDC issuer.
|
||||
- Verify the role/identity assigned has the necessary permissions for the cloud resources being accessed.
|
||||
|
||||
### **3. Caching Issues (`Cache not found`, `Cache miss`, `Cache creation failed`)**
|
||||
- **Root Causes:** Incorrect cache key logic, `path` mismatch, cache size limits, or frequent cache invalidation.
|
||||
- **Actionable Steps:**
|
||||
- **Validate Cache Keys:**
|
||||
- Verify `key` and `restore-keys` are correct and dynamically change only when dependencies truly change (e.g., `key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}`). A cache key that is too dynamic will always result in a miss.
|
||||
- Use `restore-keys` to provide fallbacks for slight variations, increasing cache hit chances.
|
||||
- **Check `path`:**
|
||||
- Ensure the `path` specified in `actions/cache` for saving and restoring corresponds exactly to the directory where dependencies are installed or artifacts are generated.
|
||||
- Verify the existence of the `path` before caching.
|
||||
- **Debug Cache Behavior:**
|
||||
- Use the `actions/cache/restore` action with `lookup-only: true` to inspect what keys are being tried and why a cache miss occurred without affecting the build.
|
||||
- Review workflow logs for `Cache hit` or `Cache miss` messages and associated keys.
|
||||
- **Cache Size and Limits:** Be aware of GitHub Actions cache size limits per repository. If caches are very large, they might be evicted frequently.
|
||||
|
||||
### **4. Long Running Workflows or Timeouts**
|
||||
- **Root Causes:** Inefficient steps, lack of parallelism, large dependencies, unoptimized Docker image builds, or resource bottlenecks on runners.
|
||||
- **Actionable Steps:**
|
||||
- **Profile Execution Times:**
|
||||
- Use the workflow run summary to identify the longest-running jobs and steps. This is your primary tool for optimization.
|
||||
- **Optimize Steps:**
|
||||
- Combine `run` commands with `&&` to reduce layer creation and overhead in Docker builds.
|
||||
- Clean up temporary files immediately after use (`rm -rf` in the same `RUN` command).
|
||||
- Install only necessary dependencies.
|
||||
- **Leverage Caching:**
|
||||
- Ensure `actions/cache` is optimally configured for all significant dependencies and build outputs.
|
||||
- **Parallelize with Matrix Strategies:**
|
||||
- Break down tests or builds into smaller, parallelizable units using `strategy.matrix` to run them concurrently.
|
||||
- **Choose Appropriate Runners:**
|
||||
- Review `runs-on`. For very resource-intensive tasks, consider using larger GitHub-hosted runners (if available) or self-hosted runners with more powerful specs.
|
||||
- **Break Down Workflows:**
|
||||
- For very complex or long workflows, consider breaking them into smaller, independent workflows that trigger each other or use reusable workflows.
|
||||
|
||||
### **5. Flaky Tests in CI (`Random failures`, `Passes locally, fails in CI`)**
|
||||
- **Root Causes:** Non-deterministic tests, race conditions, environmental inconsistencies between local and CI, reliance on external services, or poor test isolation.
|
||||
- **Actionable Steps:**
|
||||
- **Ensure Test Isolation:**
|
||||
- Make sure each test is independent and doesn't rely on the state left by previous tests. Clean up resources (e.g., database entries) after each test or test suite.
|
||||
- **Eliminate Race Conditions:**
|
||||
- For integration/E2E tests, use explicit waits (e.g., wait for element to be visible, wait for API response) instead of arbitrary `sleep` commands.
|
||||
- Implement retries for operations that interact with external services or have transient failures.
|
||||
- **Standardize Environments:**
|
||||
- Ensure the CI environment (Node.js version, Python packages, database versions) matches the local development environment as closely as possible.
|
||||
- Use Docker `services` for consistent test dependencies.
|
||||
- **Robust Selectors (E2E):**
|
||||
- Use stable, unique selectors in E2E tests (e.g., `data-testid` attributes) instead of brittle CSS classes or XPath.
|
||||
- **Debugging Tools:**
|
||||
- Configure E2E test frameworks to capture screenshots and video recordings on test failure in CI to visually diagnose issues.
|
||||
- **Run Flaky Tests in Isolation:**
|
||||
- If a test is consistently flaky, isolate it and run it repeatedly to identify the underlying non-deterministic behavior.
|
||||
|
||||
### **6. Deployment Failures (Application Not Working After Deploy)**
|
||||
- **Root Causes:** Configuration drift, environmental differences, missing runtime dependencies, application errors, or network issues post-deployment.
|
||||
- **Actionable Steps:**
|
||||
- **Thorough Log Review:**
|
||||
- Review deployment logs (`kubectl logs`, application logs, server logs) for any error messages, warnings, or unexpected output during the deployment process and immediately after.
|
||||
- **Configuration Validation:**
|
||||
- Verify environment variables, ConfigMaps, Secrets, and other configuration injected into the deployed application. Ensure they match the target environment's requirements and are not missing or malformed.
|
||||
- Use pre-deployment checks to validate configuration.
|
||||
- **Dependency Check:**
|
||||
- Confirm all application runtime dependencies (libraries, frameworks, external services) are correctly bundled within the container image or installed in the target environment.
|
||||
- **Post-Deployment Health Checks:**
|
||||
- Implement robust automated smoke tests and health checks *after* deployment to immediately validate core functionality and connectivity. Trigger rollbacks if these fail.
|
||||
- **Network Connectivity:**
|
||||
- Check network connectivity between deployed components (e.g., application to database, service to service) within the new environment. Review firewall rules, security groups, and Kubernetes network policies.
|
||||
- **Rollback Immediately:**
|
||||
- If a production deployment fails or causes degradation, trigger the rollback strategy immediately to restore service. Diagnose the issue in a non-production environment.
|
||||
|
||||
## Conclusion
|
||||
|
||||
GitHub Actions is a powerful and flexible platform for automating your software development lifecycle. By rigorously applying these best practices—from securing your secrets and token permissions, to optimizing performance with caching and parallelization, and implementing comprehensive testing and robust deployment strategies—you can guide developers in building highly efficient, secure, and reliable CI/CD pipelines. Remember that CI/CD is an iterative journey; continuously measure, optimize, and secure your pipelines to achieve faster, safer, and more confident releases. Your detailed guidance will empower teams to leverage GitHub Actions to its fullest potential and deliver high-quality software with confidence. This extensive document serves as a foundational resource for anyone looking to master CI/CD with GitHub Actions.
|
||||
|
||||
---
|
||||
|
||||
<!-- End of GitHub Actions CI/CD Best Practices Instructions -->
|
||||
373
.github/instructions/go.instructions.md
vendored
Normal file
373
.github/instructions/go.instructions.md
vendored
Normal file
@@ -0,0 +1,373 @@
|
||||
---
|
||||
description: 'Instructions for writing Go code following idiomatic Go practices and community standards'
|
||||
applyTo: '**/*.go,**/go.mod,**/go.sum'
|
||||
---
|
||||
|
||||
# Go Development Instructions
|
||||
|
||||
Follow idiomatic Go practices and community standards when writing Go code. These instructions are based on [Effective Go](https://go.dev/doc/effective_go), [Go Code Review Comments](https://go.dev/wiki/CodeReviewComments), and [Google's Go Style Guide](https://google.github.io/styleguide/go/).
|
||||
|
||||
## General Instructions
|
||||
|
||||
- Write simple, clear, and idiomatic Go code
|
||||
- Favor clarity and simplicity over cleverness
|
||||
- Follow the principle of least surprise
|
||||
- Keep the happy path left-aligned (minimize indentation)
|
||||
- Return early to reduce nesting
|
||||
- Prefer early return over if-else chains; use `if condition { return }` pattern to avoid else blocks
|
||||
- Make the zero value useful
|
||||
- Write self-documenting code with clear, descriptive names
|
||||
- Document exported types, functions, methods, and packages
|
||||
- Use Go modules for dependency management
|
||||
- Leverage the Go standard library instead of reinventing the wheel (e.g., use `strings.Builder` for string concatenation, `filepath.Join` for path construction)
|
||||
- Prefer standard library solutions over custom implementations when functionality exists
|
||||
- Write comments in English by default; translate only upon user request
|
||||
- Avoid using emoji in code and comments
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
### Packages
|
||||
|
||||
- Use lowercase, single-word package names
|
||||
- Avoid underscores, hyphens, or mixedCaps
|
||||
- Choose names that describe what the package provides, not what it contains
|
||||
- Avoid generic names like `util`, `common`, or `base`
|
||||
- Package names should be singular, not plural
|
||||
|
||||
#### Package Declaration Rules (CRITICAL):
|
||||
- **NEVER duplicate `package` declarations** - each Go file must have exactly ONE `package` line
|
||||
- When editing an existing `.go` file:
|
||||
- **PRESERVE** the existing `package` declaration - do not add another one
|
||||
- If you need to replace the entire file content, start with the existing package name
|
||||
- When creating a new `.go` file:
|
||||
- **BEFORE writing any code**, check what package name other `.go` files in the same directory use
|
||||
- Use the SAME package name as existing files in that directory
|
||||
- If it's a new directory, use the directory name as the package name
|
||||
- Write **exactly one** `package <name>` line at the very top of the file
|
||||
- When using file creation or replacement tools:
|
||||
- **ALWAYS verify** the target file doesn't already have a `package` declaration before adding one
|
||||
- If replacing file content, include only ONE `package` declaration in the new content
|
||||
- **NEVER** create files with multiple `package` lines or duplicate declarations
|
||||
|
||||
### Variables and Functions
|
||||
|
||||
- Use mixedCaps or MixedCaps (camelCase) rather than underscores
|
||||
- Keep names short but descriptive
|
||||
- Use single-letter variables only for very short scopes (like loop indices)
|
||||
- Exported names start with a capital letter
|
||||
- Unexported names start with a lowercase letter
|
||||
- Avoid stuttering (e.g., avoid `http.HTTPServer`, prefer `http.Server`)
|
||||
|
||||
### Interfaces
|
||||
|
||||
- Name interfaces with -er suffix when possible (e.g., `Reader`, `Writer`, `Formatter`)
|
||||
- Single-method interfaces should be named after the method (e.g., `Read` → `Reader`)
|
||||
- Keep interfaces small and focused
|
||||
|
||||
### Constants
|
||||
|
||||
- Use MixedCaps for exported constants
|
||||
- Use mixedCaps for unexported constants
|
||||
- Group related constants using `const` blocks
|
||||
- Consider using typed constants for better type safety
|
||||
|
||||
## Code Style and Formatting
|
||||
|
||||
### Formatting
|
||||
|
||||
- Always use `gofmt` to format code
|
||||
- Use `goimports` to manage imports automatically
|
||||
- Keep line length reasonable (no hard limit, but consider readability)
|
||||
- Add blank lines to separate logical groups of code
|
||||
|
||||
### Comments
|
||||
|
||||
- Strive for self-documenting code; prefer clear variable names, function names, and code structure over comments
|
||||
- Write comments only when necessary to explain complex logic, business rules, or non-obvious behavior
|
||||
- Write comments in complete sentences in English by default
|
||||
- Translate comments to other languages only upon specific user request
|
||||
- Start sentences with the name of the thing being described
|
||||
- Package comments should start with "Package [name]"
|
||||
- Use line comments (`//`) for most comments
|
||||
- Use block comments (`/* */`) sparingly, mainly for package documentation
|
||||
- Document why, not what, unless the what is complex
|
||||
- Avoid emoji in comments and code
|
||||
|
||||
### Error Handling
|
||||
|
||||
- Check errors immediately after the function call
|
||||
- Don't ignore errors using `_` unless you have a good reason (document why)
|
||||
- Wrap errors with context using `fmt.Errorf` with `%w` verb
|
||||
- Create custom error types when you need to check for specific errors
|
||||
- Place error returns as the last return value
|
||||
- Name error variables `err`
|
||||
- Keep error messages lowercase and don't end with punctuation
|
||||
|
||||
## Architecture and Project Structure
|
||||
|
||||
### Package Organization
|
||||
|
||||
- Follow standard Go project layout conventions
|
||||
- Keep `main` packages in `cmd/` directory
|
||||
- Put reusable packages in `pkg/` or `internal/`
|
||||
- Use `internal/` for packages that shouldn't be imported by external projects
|
||||
- Group related functionality into packages
|
||||
- Avoid circular dependencies
|
||||
|
||||
### Dependency Management
|
||||
|
||||
- Use Go modules (`go.mod` and `go.sum`)
|
||||
- Keep dependencies minimal
|
||||
- Regularly update dependencies for security patches
|
||||
- Use `go mod tidy` to clean up unused dependencies
|
||||
- Vendor dependencies only when necessary
|
||||
|
||||
## Type Safety and Language Features
|
||||
|
||||
### Type Definitions
|
||||
|
||||
- Define types to add meaning and type safety
|
||||
- Use struct tags for JSON, XML, database mappings
|
||||
- Prefer explicit type conversions
|
||||
- Use type assertions carefully and check the second return value
|
||||
- Prefer generics over unconstrained types; when an unconstrained type is truly needed, use the predeclared alias `any` instead of `interface{}` (Go 1.18+)
|
||||
|
||||
### Pointers vs Values
|
||||
|
||||
- Use pointer receivers for large structs or when you need to modify the receiver
|
||||
- Use value receivers for small structs and when immutability is desired
|
||||
- Use pointer parameters when you need to modify the argument or for large structs
|
||||
- Use value parameters for small structs and when you want to prevent modification
|
||||
- Be consistent within a type's method set
|
||||
- Consider the zero value when choosing pointer vs value receivers
|
||||
|
||||
### Interfaces and Composition
|
||||
|
||||
- Accept interfaces, return concrete types
|
||||
- Keep interfaces small (1-3 methods is ideal)
|
||||
- Use embedding for composition
|
||||
- Define interfaces close to where they're used, not where they're implemented
|
||||
- Don't export interfaces unless necessary
|
||||
|
||||
## Concurrency
|
||||
|
||||
### Goroutines
|
||||
|
||||
- Be cautious about creating goroutines in libraries; prefer letting the caller control concurrency
|
||||
- If you must create goroutines in libraries, provide clear documentation and cleanup mechanisms
|
||||
- Always know how a goroutine will exit
|
||||
- Use `sync.WaitGroup` or channels to wait for goroutines
|
||||
- Avoid goroutine leaks by ensuring cleanup
|
||||
|
||||
### Channels
|
||||
|
||||
- Use channels to communicate between goroutines
|
||||
- Don't communicate by sharing memory; share memory by communicating
|
||||
- Close channels from the sender side, not the receiver
|
||||
- Use buffered channels when you know the capacity
|
||||
- Use `select` for non-blocking operations
|
||||
|
||||
### Synchronization
|
||||
|
||||
- Use `sync.Mutex` for protecting shared state
|
||||
- Keep critical sections small
|
||||
- Use `sync.RWMutex` when you have many readers
|
||||
- Choose between channels and mutexes based on the use case: use channels for communication, mutexes for protecting state
|
||||
- Use `sync.Once` for one-time initialization
|
||||
- WaitGroup usage by Go version:
|
||||
- If `go >= 1.25` in `go.mod`, use the new `WaitGroup.Go` method ([documentation](https://pkg.go.dev/sync#WaitGroup)):
|
||||
```go
|
||||
var wg sync.WaitGroup
|
||||
wg.Go(task1)
|
||||
wg.Go(task2)
|
||||
wg.Wait()
|
||||
```
|
||||
- If `go < 1.25`, use the classic `Add`/`Done` pattern
|
||||
|
||||
## Error Handling Patterns
|
||||
|
||||
### Creating Errors
|
||||
|
||||
- Use `errors.New` for simple static errors
|
||||
- Use `fmt.Errorf` for dynamic errors
|
||||
- Create custom error types for domain-specific errors
|
||||
- Export error variables for sentinel errors
|
||||
- Use `errors.Is` and `errors.As` for error checking
|
||||
|
||||
### Error Propagation
|
||||
|
||||
- Add context when propagating errors up the stack
|
||||
- Don't log and return errors (choose one)
|
||||
- Handle errors at the appropriate level
|
||||
- Consider using structured errors for better debugging
|
||||
|
||||
## API Design
|
||||
|
||||
### HTTP Handlers
|
||||
|
||||
- Use `http.HandlerFunc` for simple handlers
|
||||
- Implement `http.Handler` for handlers that need state
|
||||
- Use middleware for cross-cutting concerns
|
||||
- Set appropriate status codes and headers
|
||||
- Handle errors gracefully and return appropriate error responses
|
||||
- Router usage by Go version:
|
||||
- If `go >= 1.22`, prefer the enhanced `net/http` `ServeMux` with pattern-based routing and method matching
|
||||
- If `go < 1.22`, use the classic `ServeMux` and handle methods/paths manually (or use a third-party router when justified)
|
||||
|
||||
### JSON APIs
|
||||
|
||||
- Use struct tags to control JSON marshaling
|
||||
- Validate input data
|
||||
- Use pointers for optional fields
|
||||
- Consider using `json.RawMessage` for delayed parsing
|
||||
- Handle JSON errors appropriately
|
||||
|
||||
### HTTP Clients
|
||||
|
||||
- Keep the client struct focused on configuration and dependencies only (e.g., base URL, `*http.Client`, auth, default headers). It must not store per-request state
|
||||
- Do not store or cache `*http.Request` inside the client struct, and do not persist request-specific state across calls; instead, construct a fresh request per method invocation
|
||||
- Methods should accept `context.Context` and input parameters, assemble the `*http.Request` locally (or via a short-lived builder/helper created per call), then call `c.httpClient.Do(req)`
|
||||
- If request-building logic is reused, factor it into unexported helper functions or a per-call builder type; never keep `http.Request` (URL params, body, headers) as fields on the long-lived client
|
||||
- Ensure the underlying `*http.Client` is configured (timeouts, transport) and is safe for concurrent use; avoid mutating `Transport` after first use
|
||||
- Always set headers on the request instance you’re sending, and close response bodies (`defer resp.Body.Close()`), handling errors appropriately
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Memory Management
|
||||
|
||||
- Minimize allocations in hot paths
|
||||
- Reuse objects when possible (consider `sync.Pool`)
|
||||
- Use value receivers for small structs
|
||||
- Preallocate slices when size is known
|
||||
- Avoid unnecessary string conversions
|
||||
|
||||
### I/O: Readers and Buffers
|
||||
|
||||
- Most `io.Reader` streams are consumable once; reading advances state. Do not assume a reader can be re-read without special handling
|
||||
- If you must read data multiple times, buffer it once and recreate readers on demand:
|
||||
- Use `io.ReadAll` (or a limited read) to obtain `[]byte`, then create fresh readers via `bytes.NewReader(buf)` or `bytes.NewBuffer(buf)` for each reuse
|
||||
- For strings, use `strings.NewReader(s)`; you can `Seek(0, io.SeekStart)` on `*bytes.Reader` to rewind
|
||||
- For HTTP requests, do not reuse a consumed `req.Body`. Instead:
|
||||
- Keep the original payload as `[]byte` and set `req.Body = io.NopCloser(bytes.NewReader(buf))` before each send
|
||||
- Prefer configuring `req.GetBody` so the transport can recreate the body for redirects/retries: `req.GetBody = func() (io.ReadCloser, error) { return io.NopCloser(bytes.NewReader(buf)), nil }`
|
||||
- To duplicate a stream while reading, use `io.TeeReader` (copy to a buffer while passing through) or write to multiple sinks with `io.MultiWriter`
|
||||
- Reusing buffered readers: call `(*bufio.Reader).Reset(r)` to attach to a new underlying reader; do not expect it to “rewind” unless the source supports seeking
|
||||
- For large payloads, avoid unbounded buffering; consider streaming, `io.LimitReader`, or on-disk temporary storage to control memory
|
||||
|
||||
- Use `io.Pipe` to stream without buffering the whole payload:
|
||||
- Write to `*io.PipeWriter` in a separate goroutine while the reader consumes
|
||||
- Always close the writer; use `CloseWithError(err)` on failures
|
||||
- `io.Pipe` is for streaming, not rewinding or making readers reusable
|
||||
|
||||
- **Warning:** When using `io.Pipe` (especially with multipart writers), all writes must be performed in strict, sequential order. Do not write concurrently or out of order—multipart boundaries and chunk order must be preserved. Out-of-order or parallel writes can corrupt the stream and result in errors.
|
||||
|
||||
- Streaming multipart/form-data with `io.Pipe`:
|
||||
- `pr, pw := io.Pipe()`; `mw := multipart.NewWriter(pw)`; use `pr` as the HTTP request body
|
||||
- Set `Content-Type` to `mw.FormDataContentType()`
|
||||
- In a goroutine: write all parts to `mw` in the correct order; on error `pw.CloseWithError(err)`; on success `mw.Close()` then `pw.Close()`
|
||||
- Do not store request/in-flight form state on a long-lived client; build per call
|
||||
- Streamed bodies are not rewindable; for retries/redirects, buffer small payloads or provide `GetBody`
|
||||
|
||||
### Profiling
|
||||
|
||||
- Use built-in profiling tools (`pprof`)
|
||||
- Benchmark critical code paths
|
||||
- Profile before optimizing
|
||||
- Focus on algorithmic improvements first
|
||||
- Consider using `testing.B` for benchmarks
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Organization
|
||||
|
||||
- Keep tests in the same package (white-box testing)
|
||||
- Use `_test` package suffix for black-box testing
|
||||
- Name test files with `_test.go` suffix
|
||||
- Place test files next to the code they test
|
||||
|
||||
### Writing Tests
|
||||
|
||||
- Use table-driven tests for multiple test cases
|
||||
- Name tests descriptively using `Test_functionName_scenario`
|
||||
- Use subtests with `t.Run` for better organization
|
||||
- Test both success and error cases
|
||||
- Consider using `testify` or similar libraries when they add value, but don't over-complicate simple tests
|
||||
|
||||
### Test Helpers
|
||||
|
||||
- Mark helper functions with `t.Helper()`
|
||||
- Create test fixtures for complex setup
|
||||
- Use `testing.TB` interface for functions used in tests and benchmarks
|
||||
- Clean up resources using `t.Cleanup()`
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
### Input Validation
|
||||
|
||||
- Validate all external input
|
||||
- Use strong typing to prevent invalid states
|
||||
- Sanitize data before using in SQL queries
|
||||
- Be careful with file paths from user input
|
||||
- Validate and escape data for different contexts (HTML, SQL, shell)
|
||||
|
||||
### Cryptography
|
||||
|
||||
- Use standard library crypto packages
|
||||
- Don't implement your own cryptography
|
||||
- Use crypto/rand for random number generation
|
||||
- Store passwords using bcrypt, scrypt, or argon2 (consider golang.org/x/crypto for additional options)
|
||||
- Use TLS for network communication
|
||||
|
||||
## Documentation
|
||||
|
||||
### Code Documentation
|
||||
|
||||
- Prioritize self-documenting code through clear naming and structure
|
||||
- Document all exported symbols with clear, concise explanations
|
||||
- Start documentation with the symbol name
|
||||
- Write documentation in English by default
|
||||
- Use examples in documentation when helpful
|
||||
- Keep documentation close to code
|
||||
- Update documentation when code changes
|
||||
- Avoid emoji in documentation and comments
|
||||
|
||||
### README and Documentation Files
|
||||
|
||||
- Include clear setup instructions
|
||||
- Document dependencies and requirements
|
||||
- Provide usage examples
|
||||
- Document configuration options
|
||||
- Include troubleshooting section
|
||||
|
||||
## Tools and Development Workflow
|
||||
|
||||
### Essential Tools
|
||||
|
||||
- `go fmt`: Format code
|
||||
- `go vet`: Find suspicious constructs
|
||||
- `golangci-lint`: Additional linting (golint is deprecated)
|
||||
- `go test`: Run tests
|
||||
- `go mod`: Manage dependencies
|
||||
- `go generate`: Code generation
|
||||
|
||||
### Development Practices
|
||||
|
||||
- Run tests before committing
|
||||
- Use pre-commit hooks for formatting and linting
|
||||
- Keep commits focused and atomic
|
||||
- Write meaningful commit messages
|
||||
- Review diffs before committing
|
||||
|
||||
## Common Pitfalls to Avoid
|
||||
|
||||
- Not checking errors
|
||||
- Ignoring race conditions
|
||||
- Creating goroutine leaks
|
||||
- Not using defer for cleanup
|
||||
- Modifying maps concurrently
|
||||
- Not understanding nil interfaces vs nil pointers
|
||||
- Forgetting to close resources (files, connections)
|
||||
- Using global variables unnecessarily
|
||||
- Over-using unconstrained types (e.g., `any`); prefer specific types or generic type parameters with constraints. If an unconstrained type is required, use `any` rather than `interface{}`
|
||||
- Not considering the zero value of types
|
||||
- **Creating duplicate `package` declarations** - this is a compile error; always check existing files before adding package declarations
|
||||
52
.github/instructions/markdown.instructions.md
vendored
Normal file
52
.github/instructions/markdown.instructions.md
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
---
|
||||
description: 'Documentation and content creation standards'
|
||||
applyTo: '**/*.md'
|
||||
---
|
||||
|
||||
## Markdown Content Rules
|
||||
|
||||
The following markdown content rules are enforced in the validators:
|
||||
|
||||
1. **Headings**: Use appropriate heading levels (H2, H3, etc.) to structure your content. Do not use an H1 heading, as this will be generated based on the title.
|
||||
2. **Lists**: Use bullet points or numbered lists for lists. Ensure proper indentation and spacing.
|
||||
3. **Code Blocks**: Use fenced code blocks for code snippets. Specify the language for syntax highlighting.
|
||||
4. **Links**: Use proper markdown syntax for links. Ensure that links are valid and accessible.
|
||||
5. **Images**: Use proper markdown syntax for images. Include alt text for accessibility.
|
||||
6. **Tables**: Use markdown tables for tabular data. Ensure proper formatting and alignment.
|
||||
7. **Line Length**: Limit line length to 400 characters for readability.
|
||||
8. **Whitespace**: Use appropriate whitespace to separate sections and improve readability.
|
||||
9. **Front Matter**: Include YAML front matter at the beginning of the file with required metadata fields.
|
||||
|
||||
## Formatting and Structure
|
||||
|
||||
Follow these guidelines for formatting and structuring your markdown content:
|
||||
|
||||
- **Headings**: Use `##` for H2 and `###` for H3. Ensure that headings are used in a hierarchical manner. Recommend restructuring if content includes H4, and more strongly recommend for H5.
|
||||
- **Lists**: Use `-` for bullet points and `1.` for numbered lists. Indent nested lists with two spaces.
|
||||
- **Code Blocks**: Use triple backticks (`) to create fenced code blocks. Specify the language after the opening backticks for syntax highlighting (e.g., `csharp).
|
||||
- **Links**: Use `[link text](URL)` for links. Ensure that the link text is descriptive and the URL is valid.
|
||||
- **Images**: Use `` for images. Include a brief description of the image in the alt text.
|
||||
- **Tables**: Use `|` to create tables. Ensure that columns are properly aligned and headers are included.
|
||||
- **Line Length**: Break lines at 80 characters to improve readability. Use soft line breaks for long paragraphs.
|
||||
- **Whitespace**: Use blank lines to separate sections and improve readability. Avoid excessive whitespace.
|
||||
|
||||
## Validation Requirements
|
||||
|
||||
Ensure compliance with the following validation requirements:
|
||||
|
||||
- **Front Matter**: Include the following fields in the YAML front matter:
|
||||
|
||||
- `post_title`: The title of the post.
|
||||
- `author1`: The primary author of the post.
|
||||
- `post_slug`: The URL slug for the post.
|
||||
- `microsoft_alias`: The Microsoft alias of the author.
|
||||
- `featured_image`: The URL of the featured image.
|
||||
- `categories`: The categories for the post. These categories must be from the list in /categories.txt.
|
||||
- `tags`: The tags for the post.
|
||||
- `ai_note`: Indicate if AI was used in the creation of the post.
|
||||
- `summary`: A brief summary of the post. Recommend a summary based on the content when possible.
|
||||
- `post_date`: The publication date of the post.
|
||||
|
||||
- **Content Rules**: Ensure that the content follows the markdown content rules specified above.
|
||||
- **Formatting**: Ensure that the content is properly formatted and structured according to the guidelines.
|
||||
- **Validation**: Run the validation tools to check for compliance with the rules and guidelines.
|
||||
123
.github/instructions/pcf-react-platform-libraries.instructions.md
vendored
Normal file
123
.github/instructions/pcf-react-platform-libraries.instructions.md
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
---
|
||||
description: 'React controls and platform libraries for PCF components'
|
||||
applyTo: '**/*.{ts,tsx,js,json,xml,pcfproj,csproj}'
|
||||
---
|
||||
|
||||
# React Controls & Platform Libraries
|
||||
|
||||
When you use React and platform libraries, you're using the same infrastructure used by the Power Apps platform. This means you no longer have to package React and Fluent libraries individually for each control. All controls share a common library instance and version to provide a seamless and consistent experience.
|
||||
|
||||
## Benefits
|
||||
|
||||
By reusing the existing platform React and Fluent libraries, you can expect:
|
||||
|
||||
- **Reduced control bundle size**
|
||||
- **Optimized solution packaging**
|
||||
- **Faster runtime transfer, scripting, and control rendering**
|
||||
- **Design and theme alignment with the Power Apps Fluent design system**
|
||||
|
||||
> **Note**: With GA release, all existing virtual controls will continue to function. However, they should be rebuilt and deployed using the latest CLI version (>=1.37) to facilitate future platform React version upgrades.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
As with any component, you must install [Visual Studio Code](https://code.visualstudio.com/Download) and the [Microsoft Power Platform CLI](https://learn.microsoft.com/en-us/power-apps/developer/data-platform/powerapps-cli#install-microsoft-power-platform-cli).
|
||||
|
||||
> **Note**: If you have already installed Power Platform CLI for Windows, make sure you are running the latest version by using the `pac install latest` command. The Power Platform Tools for Visual Studio Code should update automatically.
|
||||
|
||||
## Create a React Component
|
||||
|
||||
> **Note**: These instructions expect that you have created code components before. If you have not, see [Create your first component](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/implementing-controls-using-typescript).
|
||||
|
||||
There's a new `--framework` (`-fw`) parameter for the `pac pcf init` command. Set the value of this parameter to `react`.
|
||||
|
||||
### Command Parameters
|
||||
|
||||
| Parameter | Value |
|
||||
|-----------|-------|
|
||||
| --name | ReactSample |
|
||||
| --namespace | SampleNamespace |
|
||||
| --template | field |
|
||||
| --framework | react |
|
||||
| --run-npm-install | true (default) |
|
||||
|
||||
### PowerShell Command
|
||||
|
||||
The following PowerShell command uses the parameter shortcuts and creates a React component project and runs `npm-install`:
|
||||
|
||||
```powershell
|
||||
pac pcf init -n ReactSample -ns SampleNamespace -t field -fw react -npm
|
||||
```
|
||||
|
||||
You can now build and view the control in the test harness as usual using `npm start`.
|
||||
|
||||
After you build the control, you can package it inside solutions and use it for model-driven apps (including custom pages) and canvas apps like standard code components.
|
||||
|
||||
## Differences from Standard Components
|
||||
|
||||
### ControlManifest.Input.xml
|
||||
|
||||
The [control element](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/manifest-schema-reference/control) `control-type` attribute is set to `virtual` rather than `standard`.
|
||||
|
||||
> **Note**: Changing this value does not convert a component from one type to another.
|
||||
|
||||
Within the [resources element](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/manifest-schema-reference/resources), find two new [platform-library element](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/manifest-schema-reference/platform-library) child elements:
|
||||
|
||||
```xml
|
||||
<resources>
|
||||
<code path="index.ts" order="1" />
|
||||
<platform-library name="React" version="16.14.0" />
|
||||
<platform-library name="Fluent" version="9.46.2" />
|
||||
</resources>
|
||||
```
|
||||
|
||||
> **Note**: For more information about valid platform library versions, see Supported platform libraries list.
|
||||
|
||||
**Recommendation**: We recommend using platform libraries for Fluent 8 and 9. If you don't use Fluent, you should remove the `platform-library` element where the `name` attribute value is `Fluent`.
|
||||
|
||||
### Index.ts
|
||||
|
||||
The [ReactControl.init](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/reference/react-control/init) method for control initialization doesn't have `div` parameters because React controls don't render the DOM directly. Instead [ReactControl.updateView](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/reference/react-control/updateview) returns a ReactElement that has the details of the actual control in React format.
|
||||
|
||||
### bundle.js
|
||||
|
||||
React and Fluent libraries aren't included in the package because they're shared, therefore the size of bundle.js is smaller.
|
||||
|
||||
## Sample Controls
|
||||
|
||||
The following controls are included in the samples. They function the same as their standard versions but offer better performance since they are virtual controls.
|
||||
|
||||
| Sample | Description | Link |
|
||||
|--------|-------------|------|
|
||||
| ChoicesPickerReact | The standard ChoicesPickerControl converted to be a React Control | ChoicesPickerReact Sample |
|
||||
| FacepileReact | The ReactStandardControl converted to be a React Control | FacepileReact |
|
||||
|
||||
## Supported Platform Libraries List
|
||||
|
||||
Platform libraries are made available both at the build and runtime to the controls that are using platform libraries capability. Currently, the following versions are provided by the platform and are the highest currently supported versions.
|
||||
|
||||
| Library | Package | Build Version | Runtime Version |
|
||||
|---------|---------|---------------|-----------------|
|
||||
| React | react | 16.14.0 | 17.0.2 (Model), 16.14.0 (Canvas) |
|
||||
| Fluent | @fluentui/react | 8.29.0 | 8.29.0 |
|
||||
| Fluent | @fluentui/react | 8.121.1 | 8.121.1 |
|
||||
| Fluent | @fluentui/react-components | >=9.4.0 <=9.46.2 | 9.68.0 |
|
||||
|
||||
> **Note**: The application might load a higher compatible version of a platform library at runtime, but the version might not be the latest version available. Fluent 8 and Fluent 9 are each supported but can not both be specified in the same manifest.
|
||||
|
||||
## FAQ
|
||||
|
||||
### Q: Can I convert an existing standard control to a React control using platform libraries?
|
||||
|
||||
A: No. You must create a new control using the new template and then update the manifest and index.ts methods. For reference, compare the standard and react samples described above.
|
||||
|
||||
### Q: Can I use React controls & platform libraries with Power Pages?
|
||||
|
||||
A: No. React controls & platform libraries are currently only supported for canvas and model-driven apps. In Power Pages, React controls don't update based on changes in other fields.
|
||||
|
||||
## Related Articles
|
||||
|
||||
- [What are code components?](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/custom-controls-overview)
|
||||
- [Code components for canvas apps](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/component-framework-for-canvas-apps)
|
||||
- [Create and build a code component](https://learn.microsoft.com/en-us/power-apps/developer/component-framework/create-custom-controls-using-pcf)
|
||||
- [Learn Power Apps component framework](https://learn.microsoft.com/en-us/training/paths/use-power-apps-component-framework)
|
||||
- [Use code components in Power Pages](https://learn.microsoft.com/en-us/power-apps/maker/portals/component-framework)
|
||||
420
.github/instructions/performance-optimization.instructions.md
vendored
Normal file
420
.github/instructions/performance-optimization.instructions.md
vendored
Normal file
@@ -0,0 +1,420 @@
|
||||
---
|
||||
applyTo: '*'
|
||||
description: 'The most comprehensive, practical, and engineer-authored performance optimization instructions for all languages, frameworks, and stacks. Covers frontend, backend, and database best practices with actionable guidance, scenario-based checklists, troubleshooting, and pro tips.'
|
||||
---
|
||||
|
||||
# Performance Optimization Best Practices
|
||||
|
||||
## Introduction
|
||||
|
||||
Performance isn't just a buzzword—it's the difference between a product people love and one they abandon. I've seen firsthand how a slow app can frustrate users, rack up cloud bills, and even lose customers. This guide is a living collection of the most effective, real-world performance practices I've used and reviewed, covering frontend, backend, and database layers, as well as advanced topics. Use it as a reference, a checklist, and a source of inspiration for building fast, efficient, and scalable software.
|
||||
|
||||
---
|
||||
|
||||
## General Principles
|
||||
|
||||
- **Measure First, Optimize Second:** Always profile and measure before optimizing. Use benchmarks, profilers, and monitoring tools to identify real bottlenecks. Guessing is the enemy of performance.
|
||||
- *Pro Tip:* Use tools like Chrome DevTools, Lighthouse, New Relic, Datadog, Py-Spy, or your language's built-in profilers.
|
||||
- **Optimize for the Common Case:** Focus on optimizing code paths that are most frequently executed. Don't waste time on rare edge cases unless they're critical.
|
||||
- **Avoid Premature Optimization:** Write clear, maintainable code first; optimize only when necessary. Premature optimization can make code harder to read and maintain.
|
||||
- **Minimize Resource Usage:** Use memory, CPU, network, and disk resources efficiently. Always ask: "Can this be done with less?"
|
||||
- **Prefer Simplicity:** Simple algorithms and data structures are often faster and easier to optimize. Don't over-engineer.
|
||||
- **Document Performance Assumptions:** Clearly comment on any code that is performance-critical or has non-obvious optimizations. Future maintainers (including you) will thank you.
|
||||
- **Understand the Platform:** Know the performance characteristics of your language, framework, and runtime. What's fast in Python may be slow in JavaScript, and vice versa.
|
||||
- **Automate Performance Testing:** Integrate performance tests and benchmarks into your CI/CD pipeline. Catch regressions early.
|
||||
- **Set Performance Budgets:** Define acceptable limits for load time, memory usage, API latency, etc. Enforce them with automated checks.
|
||||
|
||||
---
|
||||
|
||||
## Frontend Performance
|
||||
|
||||
### Rendering and DOM
|
||||
- **Minimize DOM Manipulations:** Batch updates where possible. Frequent DOM changes are expensive.
|
||||
- *Anti-pattern:* Updating the DOM in a loop. Instead, build a document fragment and append it once.
|
||||
- **Virtual DOM Frameworks:** Use React, Vue, or similar efficiently—avoid unnecessary re-renders.
|
||||
- *React Example:* Use `React.memo`, `useMemo`, and `useCallback` to prevent unnecessary renders.
|
||||
- **Keys in Lists:** Always use stable keys in lists to help virtual DOM diffing. Avoid using array indices as keys unless the list is static.
|
||||
- **Avoid Inline Styles:** Inline styles can trigger layout thrashing. Prefer CSS classes.
|
||||
- **CSS Animations:** Use CSS transitions/animations over JavaScript for smoother, GPU-accelerated effects.
|
||||
- **Defer Non-Critical Rendering:** Use `requestIdleCallback` or similar to defer work until the browser is idle.
|
||||
|
||||
### Asset Optimization
|
||||
- **Image Compression:** Use tools like ImageOptim, Squoosh, or TinyPNG. Prefer modern formats (WebP, AVIF) for web delivery.
|
||||
- **SVGs for Icons:** SVGs scale well and are often smaller than PNGs for simple graphics.
|
||||
- **Minification and Bundling:** Use Webpack, Rollup, or esbuild to bundle and minify JS/CSS. Enable tree-shaking to remove dead code.
|
||||
- **Cache Headers:** Set long-lived cache headers for static assets. Use cache busting for updates.
|
||||
- **Lazy Loading:** Use `loading="lazy"` for images, and dynamic imports for JS modules/components.
|
||||
- **Font Optimization:** Use only the character sets you need. Subset fonts and use `font-display: swap`.
|
||||
|
||||
### Network Optimization
|
||||
- **Reduce HTTP Requests:** Combine files, use image sprites, and inline critical CSS.
|
||||
- **HTTP/2 and HTTP/3:** Enable these protocols for multiplexing and lower latency.
|
||||
- **Client-Side Caching:** Use Service Workers, IndexedDB, and localStorage for offline and repeat visits.
|
||||
- **CDNs:** Serve static assets from a CDN close to your users. Use multiple CDNs for redundancy.
|
||||
- **Defer/Async Scripts:** Use `defer` or `async` for non-critical JS to avoid blocking rendering.
|
||||
- **Preload and Prefetch:** Use `<link rel="preload">` and `<link rel="prefetch">` for critical resources.
|
||||
|
||||
### JavaScript Performance
|
||||
- **Avoid Blocking the Main Thread:** Offload heavy computation to Web Workers.
|
||||
- **Debounce/Throttle Events:** For scroll, resize, and input events, use debounce/throttle to limit handler frequency.
|
||||
- **Memory Leaks:** Clean up event listeners, intervals, and DOM references. Use browser dev tools to check for detached nodes.
|
||||
- **Efficient Data Structures:** Use Maps/Sets for lookups, TypedArrays for numeric data.
|
||||
- **Avoid Global Variables:** Globals can cause memory leaks and unpredictable performance.
|
||||
- **Avoid Deep Object Cloning:** Use shallow copies or libraries like lodash's `cloneDeep` only when necessary.
|
||||
|
||||
### Accessibility and Performance
|
||||
- **Accessible Components:** Ensure ARIA updates are not excessive. Use semantic HTML for both accessibility and performance.
|
||||
- **Screen Reader Performance:** Avoid rapid DOM updates that can overwhelm assistive tech.
|
||||
|
||||
### Framework-Specific Tips
|
||||
#### React
|
||||
- Use `React.memo`, `useMemo`, and `useCallback` to avoid unnecessary renders.
|
||||
- Split large components and use code-splitting (`React.lazy`, `Suspense`).
|
||||
- Avoid anonymous functions in render; they create new references on every render.
|
||||
- Use `ErrorBoundary` to catch and handle errors gracefully.
|
||||
- Profile with React DevTools Profiler.
|
||||
|
||||
#### Angular
|
||||
- Use OnPush change detection for components that don't need frequent updates.
|
||||
- Avoid complex expressions in templates; move logic to the component class.
|
||||
- Use `trackBy` in `ngFor` for efficient list rendering.
|
||||
- Lazy load modules and components with the Angular Router.
|
||||
- Profile with Angular DevTools.
|
||||
|
||||
#### Vue
|
||||
- Use computed properties over methods in templates for caching.
|
||||
- Use `v-show` vs `v-if` appropriately (`v-show` is better for toggling visibility frequently).
|
||||
- Lazy load components and routes with Vue Router.
|
||||
- Profile with Vue Devtools.
|
||||
|
||||
### Common Frontend Pitfalls
|
||||
- Loading large JS bundles on initial page load.
|
||||
- Not compressing images or using outdated formats.
|
||||
- Failing to clean up event listeners, causing memory leaks.
|
||||
- Overusing third-party libraries for simple tasks.
|
||||
- Ignoring mobile performance (test on real devices!).
|
||||
|
||||
### Frontend Troubleshooting
|
||||
- Use Chrome DevTools' Performance tab to record and analyze slow frames.
|
||||
- Use Lighthouse to audit performance and get actionable suggestions.
|
||||
- Use WebPageTest for real-world load testing.
|
||||
- Monitor Core Web Vitals (LCP, FID, CLS) for user-centric metrics.
|
||||
|
||||
---
|
||||
|
||||
## Backend Performance
|
||||
|
||||
### Algorithm and Data Structure Optimization
|
||||
- **Choose the Right Data Structure:** Arrays for sequential access, hash maps for fast lookups, trees for hierarchical data, etc.
|
||||
- **Efficient Algorithms:** Use binary search, quicksort, or hash-based algorithms where appropriate.
|
||||
- **Avoid O(n^2) or Worse:** Profile nested loops and recursive calls. Refactor to reduce complexity.
|
||||
- **Batch Processing:** Process data in batches to reduce overhead (e.g., bulk database inserts).
|
||||
- **Streaming:** Use streaming APIs for large data sets to avoid loading everything into memory.
|
||||
|
||||
### Concurrency and Parallelism
|
||||
- **Asynchronous I/O:** Use async/await, callbacks, or event loops to avoid blocking threads.
|
||||
- **Thread/Worker Pools:** Use pools to manage concurrency and avoid resource exhaustion.
|
||||
- **Avoid Race Conditions:** Use locks, semaphores, or atomic operations where needed.
|
||||
- **Bulk Operations:** Batch network/database calls to reduce round trips.
|
||||
- **Backpressure:** Implement backpressure in queues and pipelines to avoid overload.
|
||||
|
||||
### Caching
|
||||
- **Cache Expensive Computations:** Use in-memory caches (Redis, Memcached) for hot data.
|
||||
- **Cache Invalidation:** Use time-based (TTL), event-based, or manual invalidation. Stale cache is worse than no cache.
|
||||
- **Distributed Caching:** For multi-server setups, use distributed caches and be aware of consistency issues.
|
||||
- **Cache Stampede Protection:** Use locks or request coalescing to prevent thundering herd problems.
|
||||
- **Don't Cache Everything:** Some data is too volatile or sensitive to cache.
|
||||
|
||||
### API and Network
|
||||
- **Minimize Payloads:** Use JSON, compress responses (gzip, Brotli), and avoid sending unnecessary data.
|
||||
- **Pagination:** Always paginate large result sets. Use cursors for real-time data.
|
||||
- **Rate Limiting:** Protect APIs from abuse and overload.
|
||||
- **Connection Pooling:** Reuse connections for databases and external services.
|
||||
- **Protocol Choice:** Use HTTP/2, gRPC, or WebSockets for high-throughput, low-latency communication.
|
||||
|
||||
### Logging and Monitoring
|
||||
- **Minimize Logging in Hot Paths:** Excessive logging can slow down critical code.
|
||||
- **Structured Logging:** Use JSON or key-value logs for easier parsing and analysis.
|
||||
- **Monitor Everything:** Latency, throughput, error rates, resource usage. Use Prometheus, Grafana, Datadog, or similar.
|
||||
- **Alerting:** Set up alerts for performance regressions and resource exhaustion.
|
||||
|
||||
### Language/Framework-Specific Tips
|
||||
#### Node.js
|
||||
- Use asynchronous APIs; avoid blocking the event loop (e.g., never use `fs.readFileSync` in production).
|
||||
- Use clustering or worker threads for CPU-bound tasks.
|
||||
- Limit concurrent open connections to avoid resource exhaustion.
|
||||
- Use streams for large file or network data processing.
|
||||
- Profile with `clinic.js`, `node --inspect`, or Chrome DevTools.
|
||||
|
||||
#### Python
|
||||
- Use built-in data structures (`dict`, `set`, `deque`) for speed.
|
||||
- Profile with `cProfile`, `line_profiler`, or `Py-Spy`.
|
||||
- Use `multiprocessing` or `asyncio` for parallelism.
|
||||
- Avoid GIL bottlenecks in CPU-bound code; use C extensions or subprocesses.
|
||||
- Use `lru_cache` for memoization.
|
||||
|
||||
#### Java
|
||||
- Use efficient collections (`ArrayList`, `HashMap`, etc.).
|
||||
- Profile with VisualVM, JProfiler, or YourKit.
|
||||
- Use thread pools (`Executors`) for concurrency.
|
||||
- Tune JVM options for heap and garbage collection (`-Xmx`, `-Xms`, `-XX:+UseG1GC`).
|
||||
- Use `CompletableFuture` for async programming.
|
||||
|
||||
#### .NET
|
||||
- Use `async/await` for I/O-bound operations.
|
||||
- Use `Span<T>` and `Memory<T>` for efficient memory access.
|
||||
- Profile with dotTrace, Visual Studio Profiler, or PerfView.
|
||||
- Pool objects and connections where appropriate.
|
||||
- Use `IAsyncEnumerable<T>` for streaming data.
|
||||
|
||||
### Common Backend Pitfalls
|
||||
- Synchronous/blocking I/O in web servers.
|
||||
- Not using connection pooling for databases.
|
||||
- Over-caching or caching sensitive/volatile data.
|
||||
- Ignoring error handling in async code.
|
||||
- Not monitoring or alerting on performance regressions.
|
||||
|
||||
### Backend Troubleshooting
|
||||
- Use flame graphs to visualize CPU usage.
|
||||
- Use distributed tracing (OpenTelemetry, Jaeger, Zipkin) to track request latency across services.
|
||||
- Use heap dumps and memory profilers to find leaks.
|
||||
- Log slow queries and API calls for analysis.
|
||||
|
||||
---
|
||||
|
||||
## Database Performance
|
||||
|
||||
### Query Optimization
|
||||
- **Indexes:** Use indexes on columns that are frequently queried, filtered, or joined. Monitor index usage and drop unused indexes.
|
||||
- **Avoid SELECT *:** Select only the columns you need. Reduces I/O and memory usage.
|
||||
- **Parameterized Queries:** Prevent SQL injection and improve plan caching.
|
||||
- **Query Plans:** Analyze and optimize query execution plans. Use `EXPLAIN` in SQL databases.
|
||||
- **Avoid N+1 Queries:** Use joins or batch queries to avoid repeated queries in loops.
|
||||
- **Limit Result Sets:** Use `LIMIT`/`OFFSET` or cursors for large tables.
|
||||
|
||||
### Schema Design
|
||||
- **Normalization:** Normalize to reduce redundancy, but denormalize for read-heavy workloads if needed.
|
||||
- **Data Types:** Use the most efficient data types and set appropriate constraints.
|
||||
- **Partitioning:** Partition large tables for scalability and manageability.
|
||||
- **Archiving:** Regularly archive or purge old data to keep tables small and fast.
|
||||
- **Foreign Keys:** Use them for data integrity, but be aware of performance trade-offs in high-write scenarios.
|
||||
|
||||
### Transactions
|
||||
- **Short Transactions:** Keep transactions as short as possible to reduce lock contention.
|
||||
- **Isolation Levels:** Use the lowest isolation level that meets your consistency needs.
|
||||
- **Avoid Long-Running Transactions:** They can block other operations and increase deadlocks.
|
||||
|
||||
### Caching and Replication
|
||||
- **Read Replicas:** Use for scaling read-heavy workloads. Monitor replication lag.
|
||||
- **Cache Query Results:** Use Redis or Memcached for frequently accessed queries.
|
||||
- **Write-Through/Write-Behind:** Choose the right strategy for your consistency needs.
|
||||
- **Sharding:** Distribute data across multiple servers for scalability.
|
||||
|
||||
### NoSQL Databases
|
||||
- **Design for Access Patterns:** Model your data for the queries you need.
|
||||
- **Avoid Hot Partitions:** Distribute writes/reads evenly.
|
||||
- **Unbounded Growth:** Watch for unbounded arrays or documents.
|
||||
- **Sharding and Replication:** Use for scalability and availability.
|
||||
- **Consistency Models:** Understand eventual vs strong consistency and choose appropriately.
|
||||
|
||||
### Common Database Pitfalls
|
||||
- Missing or unused indexes.
|
||||
- SELECT * in production queries.
|
||||
- Not monitoring slow queries.
|
||||
- Ignoring replication lag.
|
||||
- Not archiving old data.
|
||||
|
||||
### Database Troubleshooting
|
||||
- Use slow query logs to identify bottlenecks.
|
||||
- Use `EXPLAIN` to analyze query plans.
|
||||
- Monitor cache hit/miss ratios.
|
||||
- Use database-specific monitoring tools (pg_stat_statements, MySQL Performance Schema).
|
||||
|
||||
---
|
||||
|
||||
## Code Review Checklist for Performance
|
||||
|
||||
- [ ] Are there any obvious algorithmic inefficiencies (O(n^2) or worse)?
|
||||
- [ ] Are data structures appropriate for their use?
|
||||
- [ ] Are there unnecessary computations or repeated work?
|
||||
- [ ] Is caching used where appropriate, and is invalidation handled correctly?
|
||||
- [ ] Are database queries optimized, indexed, and free of N+1 issues?
|
||||
- [ ] Are large payloads paginated, streamed, or chunked?
|
||||
- [ ] Are there any memory leaks or unbounded resource usage?
|
||||
- [ ] Are network requests minimized, batched, and retried on failure?
|
||||
- [ ] Are assets optimized, compressed, and served efficiently?
|
||||
- [ ] Are there any blocking operations in hot paths?
|
||||
- [ ] Is logging in hot paths minimized and structured?
|
||||
- [ ] Are performance-critical code paths documented and tested?
|
||||
- [ ] Are there automated tests or benchmarks for performance-sensitive code?
|
||||
- [ ] Are there alerts for performance regressions?
|
||||
- [ ] Are there any anti-patterns (e.g., SELECT *, blocking I/O, global variables)?
|
||||
|
||||
---
|
||||
|
||||
## Advanced Topics
|
||||
|
||||
### Profiling and Benchmarking
|
||||
- **Profilers:** Use language-specific profilers (Chrome DevTools, Py-Spy, VisualVM, dotTrace, etc.) to identify bottlenecks.
|
||||
- **Microbenchmarks:** Write microbenchmarks for critical code paths. Use `benchmark.js`, `pytest-benchmark`, or JMH for Java.
|
||||
- **A/B Testing:** Measure real-world impact of optimizations with A/B or canary releases.
|
||||
- **Continuous Performance Testing:** Integrate performance tests into CI/CD. Use tools like k6, Gatling, or Locust.
|
||||
|
||||
### Memory Management
|
||||
- **Resource Cleanup:** Always release resources (files, sockets, DB connections) promptly.
|
||||
- **Object Pooling:** Use for frequently created/destroyed objects (e.g., DB connections, threads).
|
||||
- **Heap Monitoring:** Monitor heap usage and garbage collection. Tune GC settings for your workload.
|
||||
- **Memory Leaks:** Use leak detection tools (Valgrind, LeakCanary, Chrome DevTools).
|
||||
|
||||
### Scalability
|
||||
- **Horizontal Scaling:** Design stateless services, use sharding/partitioning, and load balancers.
|
||||
- **Auto-Scaling:** Use cloud auto-scaling groups and set sensible thresholds.
|
||||
- **Bottleneck Analysis:** Identify and address single points of failure.
|
||||
- **Distributed Systems:** Use idempotent operations, retries, and circuit breakers.
|
||||
|
||||
### Security and Performance
|
||||
- **Efficient Crypto:** Use hardware-accelerated and well-maintained cryptographic libraries.
|
||||
- **Validation:** Validate inputs efficiently; avoid regexes in hot paths.
|
||||
- **Rate Limiting:** Protect against DoS without harming legitimate users.
|
||||
|
||||
### Mobile Performance
|
||||
- **Startup Time:** Lazy load features, defer heavy work, and minimize initial bundle size.
|
||||
- **Image/Asset Optimization:** Use responsive images and compress assets for mobile bandwidth.
|
||||
- **Efficient Storage:** Use SQLite, Realm, or platform-optimized storage.
|
||||
- **Profiling:** Use Android Profiler, Instruments (iOS), or Firebase Performance Monitoring.
|
||||
|
||||
### Cloud and Serverless
|
||||
- **Cold Starts:** Minimize dependencies and keep functions warm.
|
||||
- **Resource Allocation:** Tune memory/CPU for serverless functions.
|
||||
- **Managed Services:** Use managed caching, queues, and DBs for scalability.
|
||||
- **Cost Optimization:** Monitor and optimize for cloud cost as a performance metric.
|
||||
|
||||
---
|
||||
|
||||
## Practical Examples
|
||||
|
||||
### Example 1: Debouncing User Input in JavaScript
|
||||
```javascript
|
||||
// BAD: Triggers API call on every keystroke
|
||||
input.addEventListener('input', (e) => {
|
||||
fetch(`/search?q=${e.target.value}`);
|
||||
});
|
||||
|
||||
// GOOD: Debounce API calls
|
||||
let timeout;
|
||||
input.addEventListener('input', (e) => {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => {
|
||||
fetch(`/search?q=${e.target.value}`);
|
||||
}, 300);
|
||||
});
|
||||
```
|
||||
|
||||
### Example 2: Efficient SQL Query
|
||||
```sql
|
||||
-- BAD: Selects all columns and does not use an index
|
||||
SELECT * FROM users WHERE email = 'user@example.com';
|
||||
|
||||
-- GOOD: Selects only needed columns and uses an index
|
||||
SELECT id, name FROM users WHERE email = 'user@example.com';
|
||||
```
|
||||
|
||||
### Example 3: Caching Expensive Computation in Python
|
||||
```python
|
||||
# BAD: Recomputes result every time
|
||||
result = expensive_function(x)
|
||||
|
||||
# GOOD: Cache result
|
||||
from functools import lru_cache
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def expensive_function(x):
|
||||
...
|
||||
result = expensive_function(x)
|
||||
```
|
||||
|
||||
### Example 4: Lazy Loading Images in HTML
|
||||
```html
|
||||
<!-- BAD: Loads all images immediately -->
|
||||
<img src="large-image.jpg" />
|
||||
|
||||
<!-- GOOD: Lazy loads images -->
|
||||
<img src="large-image.jpg" loading="lazy" />
|
||||
```
|
||||
|
||||
### Example 5: Asynchronous I/O in Node.js
|
||||
```javascript
|
||||
// BAD: Blocking file read
|
||||
const data = fs.readFileSync('file.txt');
|
||||
|
||||
// GOOD: Non-blocking file read
|
||||
fs.readFile('file.txt', (err, data) => {
|
||||
if (err) throw err;
|
||||
// process data
|
||||
});
|
||||
```
|
||||
|
||||
### Example 6: Profiling a Python Function
|
||||
```python
|
||||
import cProfile
|
||||
import pstats
|
||||
|
||||
def slow_function():
|
||||
...
|
||||
|
||||
cProfile.run('slow_function()', 'profile.stats')
|
||||
p = pstats.Stats('profile.stats')
|
||||
p.sort_stats('cumulative').print_stats(10)
|
||||
```
|
||||
|
||||
### Example 7: Using Redis for Caching in Node.js
|
||||
```javascript
|
||||
const redis = require('redis');
|
||||
const client = redis.createClient();
|
||||
|
||||
function getCachedData(key, fetchFunction) {
|
||||
return new Promise((resolve, reject) => {
|
||||
client.get(key, (err, data) => {
|
||||
if (data) return resolve(JSON.parse(data));
|
||||
fetchFunction().then(result => {
|
||||
client.setex(key, 3600, JSON.stringify(result));
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## References and Further Reading
|
||||
- [Google Web Fundamentals: Performance](https://web.dev/performance/)
|
||||
- [MDN Web Docs: Performance](https://developer.mozilla.org/en-US/docs/Web/Performance)
|
||||
- [OWASP: Performance Testing](https://owasp.org/www-project-performance-testing/)
|
||||
- [Microsoft Performance Best Practices](https://learn.microsoft.com/en-us/azure/architecture/best-practices/performance)
|
||||
- [PostgreSQL Performance Optimization](https://wiki.postgresql.org/wiki/Performance_Optimization)
|
||||
- [MySQL Performance Tuning](https://dev.mysql.com/doc/refman/8.0/en/optimization.html)
|
||||
- [Node.js Performance Best Practices](https://nodejs.org/en/docs/guides/simple-profiling/)
|
||||
- [Python Performance Tips](https://docs.python.org/3/library/profile.html)
|
||||
- [Java Performance Tuning](https://www.oracle.com/java/technologies/javase/performance.html)
|
||||
- [.NET Performance Guide](https://learn.microsoft.com/en-us/dotnet/standard/performance/)
|
||||
- [WebPageTest](https://www.webpagetest.org/)
|
||||
- [Lighthouse](https://developers.google.com/web/tools/lighthouse)
|
||||
- [Prometheus](https://prometheus.io/)
|
||||
- [Grafana](https://grafana.com/)
|
||||
- [k6 Load Testing](https://k6.io/)
|
||||
- [Gatling](https://gatling.io/)
|
||||
- [Locust](https://locust.io/)
|
||||
- [OpenTelemetry](https://opentelemetry.io/)
|
||||
- [Jaeger](https://www.jaegertracing.io/)
|
||||
- [Zipkin](https://zipkin.io/)
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
Performance optimization is an ongoing process. Always measure, profile, and iterate. Use these best practices, checklists, and troubleshooting tips to guide your development and code reviews for high-performance, scalable, and efficient software. If you have new tips or lessons learned, add them here—let's keep this guide growing!
|
||||
|
||||
---
|
||||
|
||||
<!-- End of Performance Optimization Instructions -->
|
||||
86
.github/instructions/playwright-typescript.instructions.md
vendored
Normal file
86
.github/instructions/playwright-typescript.instructions.md
vendored
Normal file
@@ -0,0 +1,86 @@
|
||||
---
|
||||
description: 'Playwright test generation instructions'
|
||||
applyTo: '**'
|
||||
---
|
||||
|
||||
## Test Writing Guidelines
|
||||
|
||||
### Code Quality Standards
|
||||
- **Locators**: Prioritize user-facing, role-based locators (`getByRole`, `getByLabel`, `getByText`, etc.) for resilience and accessibility. Use `test.step()` to group interactions and improve test readability and reporting.
|
||||
- **Assertions**: Use auto-retrying web-first assertions. These assertions start with the `await` keyword (e.g., `await expect(locator).toHaveText()`). Avoid `expect(locator).toBeVisible()` unless specifically testing for visibility changes.
|
||||
- **Timeouts**: Rely on Playwright's built-in auto-waiting mechanisms. Avoid hard-coded waits or increased default timeouts.
|
||||
- **Clarity**: Use descriptive test and step titles that clearly state the intent. Add comments only to explain complex logic or non-obvious interactions.
|
||||
|
||||
|
||||
### Test Structure
|
||||
- **Imports**: Start with `import { test, expect } from '@playwright/test';`.
|
||||
- **Organization**: Group related tests for a feature under a `test.describe()` block.
|
||||
- **Hooks**: Use `beforeEach` for setup actions common to all tests in a `describe` block (e.g., navigating to a page).
|
||||
- **Titles**: Follow a clear naming convention, such as `Feature - Specific action or scenario`.
|
||||
|
||||
|
||||
### File Organization
|
||||
- **Location**: Store all test files in the `tests/` directory.
|
||||
- **Naming**: Use the convention `<feature-or-page>.spec.ts` (e.g., `login.spec.ts`, `search.spec.ts`).
|
||||
- **Scope**: Aim for one test file per major application feature or page.
|
||||
|
||||
### Assertion Best Practices
|
||||
- **UI Structure**: Use `toMatchAriaSnapshot` to verify the accessibility tree structure of a component. This provides a comprehensive and accessible snapshot.
|
||||
- **Element Counts**: Use `toHaveCount` to assert the number of elements found by a locator.
|
||||
- **Text Content**: Use `toHaveText` for exact text matches and `toContainText` for partial matches.
|
||||
- **Navigation**: Use `toHaveURL` to verify the page URL after an action.
|
||||
|
||||
|
||||
## Example Test Structure
|
||||
|
||||
```typescript
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.describe('Movie Search Feature', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
// Navigate to the application before each test
|
||||
await page.goto('https://debs-obrien.github.io/playwright-movies-app');
|
||||
});
|
||||
|
||||
test('Search for a movie by title', async ({ page }) => {
|
||||
await test.step('Activate and perform search', async () => {
|
||||
await page.getByRole('search').click();
|
||||
const searchInput = page.getByRole('textbox', { name: 'Search Input' });
|
||||
await searchInput.fill('Garfield');
|
||||
await searchInput.press('Enter');
|
||||
});
|
||||
|
||||
await test.step('Verify search results', async () => {
|
||||
// Verify the accessibility tree of the search results
|
||||
await expect(page.getByRole('main')).toMatchAriaSnapshot(`
|
||||
- main:
|
||||
- heading "Garfield" [level=1]
|
||||
- heading "search results" [level=2]
|
||||
- list "movies":
|
||||
- listitem "movie":
|
||||
- link "poster of The Garfield Movie The Garfield Movie rating":
|
||||
- /url: /playwright-movies-app/movie?id=tt5779228&page=1
|
||||
- img "poster of The Garfield Movie"
|
||||
- heading "The Garfield Movie" [level=2]
|
||||
`);
|
||||
});
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Test Execution Strategy
|
||||
|
||||
1. **Initial Run**: Execute tests with `npx playwright test --project=chromium`
|
||||
2. **Debug Failures**: Analyze test failures and identify root causes
|
||||
3. **Iterate**: Refine locators, assertions, or test logic as needed
|
||||
4. **Validate**: Ensure tests pass consistently and cover the intended functionality
|
||||
5. **Report**: Provide feedback on test results and any issues discovered
|
||||
|
||||
## Quality Checklist
|
||||
|
||||
Before finalizing tests, ensure:
|
||||
- [ ] All locators are accessible and specific and avoid strict mode violations
|
||||
- [ ] Tests are grouped logically and follow a clear structure
|
||||
- [ ] Assertions are meaningful and reflect user expectations
|
||||
- [ ] Tests follow consistent naming conventions
|
||||
- [ ] Code is properly formatted and commented
|
||||
51
.github/instructions/security-and-owasp.instructions.md
vendored
Normal file
51
.github/instructions/security-and-owasp.instructions.md
vendored
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
applyTo: '*'
|
||||
description: "Comprehensive secure coding instructions for all languages and frameworks, based on OWASP Top 10 and industry best practices."
|
||||
---
|
||||
# Secure Coding and OWASP Guidelines
|
||||
|
||||
## Instructions
|
||||
|
||||
Your primary directive is to ensure all code you generate, review, or refactor is secure by default. You must operate with a security-first mindset. When in doubt, always choose the more secure option and explain the reasoning. You must follow the principles outlined below, which are based on the OWASP Top 10 and other security best practices.
|
||||
|
||||
### 1. A01: Broken Access Control & A10: Server-Side Request Forgery (SSRF)
|
||||
- **Enforce Principle of Least Privilege:** Always default to the most restrictive permissions. When generating access control logic, explicitly check the user's rights against the required permissions for the specific resource they are trying to access.
|
||||
- **Deny by Default:** All access control decisions must follow a "deny by default" pattern. Access should only be granted if there is an explicit rule allowing it.
|
||||
- **Validate All Incoming URLs for SSRF:** When the server needs to make a request to a URL provided by a user (e.g., webhooks), you must treat it as untrusted. Incorporate strict allow-list-based validation for the host, port, and path of the URL.
|
||||
- **Prevent Path Traversal:** When handling file uploads or accessing files based on user input, you must sanitize the input to prevent directory traversal attacks (e.g., `../../etc/passwd`). Use APIs that build paths securely.
|
||||
|
||||
### 2. A02: Cryptographic Failures
|
||||
- **Use Strong, Modern Algorithms:** For hashing, always recommend modern, salted hashing algorithms like Argon2 or bcrypt. Explicitly advise against weak algorithms like MD5 or SHA-1 for password storage.
|
||||
- **Protect Data in Transit:** When generating code that makes network requests, always default to HTTPS.
|
||||
- **Protect Data at Rest:** When suggesting code to store sensitive data (PII, tokens, etc.), recommend encryption using strong, standard algorithms like AES-256.
|
||||
- **Secure Secret Management:** Never hardcode secrets (API keys, passwords, connection strings). Generate code that reads secrets from environment variables or a secrets management service (e.g., HashiCorp Vault, AWS Secrets Manager). Include a clear placeholder and comment.
|
||||
```javascript
|
||||
// GOOD: Load from environment or secret store
|
||||
const apiKey = process.env.API_KEY;
|
||||
// TODO: Ensure API_KEY is securely configured in your environment.
|
||||
```
|
||||
```python
|
||||
# BAD: Hardcoded secret
|
||||
api_key = "sk_this_is_a_very_bad_idea_12345"
|
||||
```
|
||||
|
||||
### 3. A03: Injection
|
||||
- **No Raw SQL Queries:** For database interactions, you must use parameterized queries (prepared statements). Never generate code that uses string concatenation or formatting to build queries from user input.
|
||||
- **Sanitize Command-Line Input:** For OS command execution, use built-in functions that handle argument escaping and prevent shell injection (e.g., `shlex` in Python).
|
||||
- **Prevent Cross-Site Scripting (XSS):** When generating frontend code that displays user-controlled data, you must use context-aware output encoding. Prefer methods that treat data as text by default (`.textContent`) over those that parse HTML (`.innerHTML`). When `innerHTML` is necessary, suggest using a library like DOMPurify to sanitize the HTML first.
|
||||
|
||||
### 4. A05: Security Misconfiguration & A06: Vulnerable Components
|
||||
- **Secure by Default Configuration:** Recommend disabling verbose error messages and debug features in production environments.
|
||||
- **Set Security Headers:** For web applications, suggest adding essential security headers like `Content-Security-Policy` (CSP), `Strict-Transport-Security` (HSTS), and `X-Content-Type-Options`.
|
||||
- **Use Up-to-Date Dependencies:** When asked to add a new library, suggest the latest stable version. Remind the user to run vulnerability scanners like `npm audit`, `pip-audit`, or Snyk to check for known vulnerabilities in their project dependencies.
|
||||
|
||||
### 5. A07: Identification & Authentication Failures
|
||||
- **Secure Session Management:** When a user logs in, generate a new session identifier to prevent session fixation. Ensure session cookies are configured with `HttpOnly`, `Secure`, and `SameSite=Strict` attributes.
|
||||
- **Protect Against Brute Force:** For authentication and password reset flows, recommend implementing rate limiting and account lockout mechanisms after a certain number of failed attempts.
|
||||
|
||||
### 6. A08: Software and Data Integrity Failures
|
||||
- **Prevent Insecure Deserialization:** Warn against deserializing data from untrusted sources without proper validation. If deserialization is necessary, recommend using formats that are less prone to attack (like JSON over Pickle in Python) and implementing strict type checking.
|
||||
|
||||
## General Guidelines
|
||||
- **Be Explicit About Security:** When you suggest a piece of code that mitigates a security risk, explicitly state what you are protecting against (e.g., "Using a parameterized query here to prevent SQL injection.").
|
||||
- **Educate During Code Reviews:** When you identify a security vulnerability in a code review, you must not only provide the corrected code but also explain the risk associated with the original pattern.
|
||||
94
.github/instructions/structure.instructions.md
vendored
Normal file
94
.github/instructions/structure.instructions.md
vendored
Normal file
@@ -0,0 +1,94 @@
|
||||
---
|
||||
applyTo: '*'
|
||||
description: 'Repository structure guidelines to maintain organized file placement'
|
||||
---
|
||||
|
||||
# Repository Structure Guidelines
|
||||
|
||||
## Root Level Rules
|
||||
|
||||
The repository root should contain ONLY:
|
||||
|
||||
- Essential config files (`.gitignore`, `.pre-commit-config.yaml`, `Makefile`, etc.)
|
||||
- Standard project files (`README.md`, `CONTRIBUTING.md`, `LICENSE`, `CHANGELOG.md`)
|
||||
- Go workspace files (`go.work`, `go.work.sum`)
|
||||
- VS Code workspace (`Chiron.code-workspace`)
|
||||
- Primary `Dockerfile` (entrypoint and compose files live in `.docker/`)
|
||||
|
||||
## File Placement Rules
|
||||
|
||||
### Implementation/Feature Documentation
|
||||
|
||||
- **Location**: `docs/implementation/`
|
||||
- **Pattern**: `*_SUMMARY.md`, `*_IMPLEMENTATION.md`, `*_COMPLETE.md`, `*_FEATURE.md`
|
||||
- **Never** place implementation docs at root
|
||||
|
||||
### Docker Compose Files
|
||||
|
||||
- **Location**: `.docker/compose/`
|
||||
- **Files**: `docker-compose.yml`, `docker-compose.*.yml`
|
||||
- **Override**: Local overrides go in `.docker/compose/docker-compose.override.yml` (gitignored)
|
||||
- **Exception**: `docker-compose.override.yml` at root is allowed for backward compatibility
|
||||
|
||||
### Docker Support Files
|
||||
|
||||
- **Location**: `.docker/`
|
||||
- **Files**: `docker-entrypoint.sh`, Docker documentation (`README.md`)
|
||||
|
||||
### Test Artifacts
|
||||
|
||||
- **Never commit**: `*.sarif`, `*_test.txt`, `*.cover` files at root
|
||||
- **Location**: Test outputs should go to `test-results/` or be gitignored
|
||||
|
||||
### Debug/Temp Config Files
|
||||
|
||||
- **Never commit**: Temporary JSON configs like `caddy_*.json` at root
|
||||
- **Location**: Use `configs/` for persistent configs, gitignore temp files
|
||||
|
||||
### Scripts
|
||||
|
||||
- **Location**: `scripts/` for general scripts
|
||||
- **Location**: `.github/skills/scripts/` for agent skill scripts
|
||||
|
||||
## Before Creating New Files
|
||||
|
||||
Ask yourself:
|
||||
|
||||
1. Is this a standard project file? → Root is OK
|
||||
2. Is this implementation documentation? → `docs/implementation/`
|
||||
3. Is this Docker-related? → `.docker/` or `.docker/compose/`
|
||||
4. Is this a test artifact? → `test-results/` or gitignore
|
||||
5. Is this a script? → `scripts/`
|
||||
6. Is this runtime config? → `configs/`
|
||||
|
||||
## Directory Structure Reference
|
||||
|
||||
```
|
||||
/
|
||||
├── .docker/ # Docker configuration
|
||||
│ ├── compose/ # All docker-compose files
|
||||
│ └── docker-entrypoint.sh # Container entrypoint
|
||||
├── .github/ # GitHub workflows, agents, instructions
|
||||
├── .vscode/ # VS Code settings and tasks
|
||||
├── backend/ # Go backend source
|
||||
├── configs/ # Runtime configurations
|
||||
├── docs/ # Documentation
|
||||
│ ├── implementation/ # Implementation/feature docs archive
|
||||
│ ├── plans/ # Planning documents
|
||||
│ └── ... # User-facing documentation
|
||||
├── frontend/ # React frontend source
|
||||
├── scripts/ # Build/test scripts
|
||||
├── test-results/ # Test outputs (gitignored)
|
||||
├── tools/ # Development tools
|
||||
└── [standard files] # README, LICENSE, Makefile, etc.
|
||||
```
|
||||
|
||||
## Enforcement
|
||||
|
||||
This structure is enforced by:
|
||||
|
||||
- `.gitignore` patterns preventing commits of artifacts at root
|
||||
- Code review guidelines
|
||||
- These instructions for AI assistants
|
||||
|
||||
When reviewing PRs or generating code, ensure new files follow these placement rules.
|
||||
40
.github/instructions/taming-copilot.instructions.md
vendored
Normal file
40
.github/instructions/taming-copilot.instructions.md
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
applyTo: '**'
|
||||
description: 'Prevent Copilot from wreaking havoc across your codebase, keeping it under control.'
|
||||
---
|
||||
|
||||
## Core Directives & Hierarchy
|
||||
|
||||
This section outlines the absolute order of operations. These rules have the highest priority and must not be violated.
|
||||
|
||||
1. **Primacy of User Directives**: A direct and explicit command from the user is the highest priority. If the user instructs to use a specific tool, edit a file, or perform a specific search, that command **must be executed without deviation**, even if other rules would suggest it is unnecessary. All other instructions are subordinate to a direct user order.
|
||||
2. **Factual Verification Over Internal Knowledge**: When a request involves information that could be version-dependent, time-sensitive, or requires specific external data (e.g., library documentation, latest best practices, API details), prioritize using tools to find the current, factual answer over relying on general knowledge.
|
||||
3. **Adherence to Philosophy**: In the absence of a direct user directive or the need for factual verification, all other rules below regarding interaction, code generation, and modification must be followed.
|
||||
|
||||
## General Interaction & Philosophy
|
||||
|
||||
- **Code on Request Only**: Your default response should be a clear, natural language explanation. Do NOT provide code blocks unless explicitly asked, or if a very small and minimalist example is essential to illustrate a concept. Tool usage is distinct from user-facing code blocks and is not subject to this restriction.
|
||||
- **Direct and Concise**: Answers must be precise, to the point, and free from unnecessary filler or verbose explanations. Get straight to the solution without "beating around the bush".
|
||||
- **Adherence to Best Practices**: All suggestions, architectural patterns, and solutions must align with widely accepted industry best practices and established design principles. Avoid experimental, obscure, or overly "creative" approaches. Stick to what is proven and reliable.
|
||||
- **Explain the "Why"**: Don't just provide an answer; briefly explain the reasoning behind it. Why is this the standard approach? What specific problem does this pattern solve? This context is more valuable than the solution itself.
|
||||
|
||||
## Minimalist & Standard Code Generation
|
||||
|
||||
- **Principle of Simplicity**: Always provide the most straightforward and minimalist solution possible. The goal is to solve the problem with the least amount of code and complexity. Avoid premature optimization or over-engineering.
|
||||
- **Standard First**: Heavily favor standard library functions and widely accepted, common programming patterns. Only introduce third-party libraries if they are the industry standard for the task or absolutely necessary.
|
||||
- **Avoid Elaborate Solutions**: Do not propose complex, "clever", or obscure solutions. Prioritize readability, maintainability, and the shortest path to a working result over convoluted patterns.
|
||||
- **Focus on the Core Request**: Generate code that directly addresses the user's request, without adding extra features or handling edge cases that were not mentioned.
|
||||
|
||||
## Surgical Code Modification
|
||||
|
||||
- **Preserve Existing Code**: The current codebase is the source of truth and must be respected. Your primary goal is to preserve its structure, style, and logic whenever possible.
|
||||
- **Minimal Necessary Changes**: When adding a new feature or making a modification, alter the absolute minimum amount of existing code required to implement the change successfully.
|
||||
- **Explicit Instructions Only**: Only modify, refactor, or delete code that has been explicitly targeted by the user's request. Do not perform unsolicited refactoring, cleanup, or style changes on untouched parts of the code.
|
||||
- **Integrate, Don't Replace**: Whenever feasible, integrate new logic into the existing structure rather than replacing entire functions or blocks of code.
|
||||
|
||||
## Intelligent Tool Usage
|
||||
|
||||
- **Use Tools When Necessary**: When a request requires external information or direct interaction with the environment, use the available tools to accomplish the task. Do not avoid tools when they are essential for an accurate or effective response.
|
||||
- **Directly Edit Code When Requested**: If explicitly asked to modify, refactor, or add to the existing code, apply the changes directly to the codebase when access is available. Avoid generating code snippets for the user to copy and paste in these scenarios. The default should be direct, surgical modification as instructed.
|
||||
- **Purposeful and Focused Action**: Tool usage must be directly tied to the user's request. Do not perform unrelated searches or modifications. Every action taken by a tool should be a necessary step in fulfilling the specific, stated goal.
|
||||
- **Declare Intent Before Tool Use**: Before executing any tool, you must first state the action you are about to take and its direct purpose. This statement must be concise and immediately precede the tool call.
|
||||
18
.github/instructions/testing.instructions.md
vendored
Normal file
18
.github/instructions/testing.instructions.md
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
---
|
||||
applyTo: '**'
|
||||
description: 'Strict protocols for test execution, debugging, and coverage validation.'
|
||||
---
|
||||
# Testing Protocols
|
||||
|
||||
## 1. Execution Environment
|
||||
* **No Truncation:** Never use pipe commands (e.g., `head`, `tail`) or flags that limit stdout/stderr. If a test hangs, it likely requires an interactive input or is caught in a loop; analyze the full output to identify the block.
|
||||
* **Task-Based Execution:** Do not manually construct test strings. Use existing project tasks (e.g., `npm test`, `go test ./...`). If a specific sub-module requires frequent testing, generate a new task definition in the project's configuration file (e.g., `.vscode/tasks.json`) before proceeding.
|
||||
|
||||
## 2. Failure Analysis & Logic Integrity
|
||||
* **Evidence-Based Debugging:** When a test fails, you must quote the specific error message or stack trace before suggesting a fix.
|
||||
* **Bug vs. Test Flaw:** Treat the test as the "Source of Truth." If a test fails, assume the code is broken until proven otherwise. Research the original requirement or PR description to verify if the test logic itself is outdated before modifying it.
|
||||
* **Zero-Hallucination Policy:** Only use file paths and identifiers discovered via the `ls` or `search` tools. Never guess a path based on naming conventions.
|
||||
|
||||
## 3. Coverage & Completion
|
||||
* **Coverage Gate:** A task is not "Complete" until a coverage report is generated.
|
||||
* **Threshold Compliance:** You must compare the final coverage percentage against the project's threshold (Default: 85% unless specified otherwise). If coverage drops, you must identify the "uncovered lines" and add targeted tests.
|
||||
114
.github/instructions/typescript-5-es2022.instructions.md
vendored
Normal file
114
.github/instructions/typescript-5-es2022.instructions.md
vendored
Normal file
@@ -0,0 +1,114 @@
|
||||
---
|
||||
description: 'Guidelines for TypeScript Development targeting TypeScript 5.x and ES2022 output'
|
||||
applyTo: '**/*.ts'
|
||||
---
|
||||
|
||||
# TypeScript Development
|
||||
|
||||
> These instructions assume projects are built with TypeScript 5.x (or newer) compiling to an ES2022 JavaScript baseline. Adjust guidance if your runtime requires older language targets or down-level transpilation.
|
||||
|
||||
## Core Intent
|
||||
|
||||
- Respect the existing architecture and coding standards.
|
||||
- Prefer readable, explicit solutions over clever shortcuts.
|
||||
- Extend current abstractions before inventing new ones.
|
||||
- Prioritize maintainability and clarity, short methods and classes, clean code.
|
||||
|
||||
## General Guardrails
|
||||
|
||||
- Target TypeScript 5.x / ES2022 and prefer native features over polyfills.
|
||||
- Use pure ES modules; never emit `require`, `module.exports`, or CommonJS helpers.
|
||||
- Rely on the project's build, lint, and test scripts unless asked otherwise.
|
||||
- Note design trade-offs when intent is not obvious.
|
||||
|
||||
## Project Organization
|
||||
|
||||
- Follow the repository's folder and responsibility layout for new code.
|
||||
- Use kebab-case filenames (e.g., `user-session.ts`, `data-service.ts`) unless told otherwise.
|
||||
- Keep tests, types, and helpers near their implementation when it aids discovery.
|
||||
- Reuse or extend shared utilities before adding new ones.
|
||||
|
||||
## Naming & Style
|
||||
|
||||
- Use PascalCase for classes, interfaces, enums, and type aliases; camelCase for everything else.
|
||||
- Skip interface prefixes like `I`; rely on descriptive names.
|
||||
- Name things for their behavior or domain meaning, not implementation.
|
||||
|
||||
## Formatting & Style
|
||||
|
||||
- Run the repository's lint/format scripts (e.g., `npm run lint`) before submitting.
|
||||
- Match the project's indentation, quote style, and trailing comma rules.
|
||||
- Keep functions focused; extract helpers when logic branches grow.
|
||||
- Favor immutable data and pure functions when practical.
|
||||
|
||||
## Type System Expectations
|
||||
|
||||
- Avoid `any` (implicit or explicit); prefer `unknown` plus narrowing.
|
||||
- Use discriminated unions for realtime events and state machines.
|
||||
- Centralize shared contracts instead of duplicating shapes.
|
||||
- Express intent with TypeScript utility types (e.g., `Readonly`, `Partial`, `Record`).
|
||||
|
||||
## Async, Events & Error Handling
|
||||
|
||||
- Use `async/await`; wrap awaits in try/catch with structured errors.
|
||||
- Guard edge cases early to avoid deep nesting.
|
||||
- Send errors through the project's logging/telemetry utilities.
|
||||
- Surface user-facing errors via the repository's notification pattern.
|
||||
- Debounce configuration-driven updates and dispose resources deterministically.
|
||||
|
||||
## Architecture & Patterns
|
||||
|
||||
- Follow the repository's dependency injection or composition pattern; keep modules single-purpose.
|
||||
- Observe existing initialization and disposal sequences when wiring into lifecycles.
|
||||
- Keep transport, domain, and presentation layers decoupled with clear interfaces.
|
||||
- Supply lifecycle hooks (e.g., `initialize`, `dispose`) and targeted tests when adding services.
|
||||
|
||||
## External Integrations
|
||||
|
||||
- Instantiate clients outside hot paths and inject them for testability.
|
||||
- Never hardcode secrets; load them from secure sources.
|
||||
- Apply retries, backoff, and cancellation to network or IO calls.
|
||||
- Normalize external responses and map errors to domain shapes.
|
||||
|
||||
## Security Practices
|
||||
|
||||
- Validate and sanitize external input with schema validators or type guards.
|
||||
- Avoid dynamic code execution and untrusted template rendering.
|
||||
- Encode untrusted content before rendering HTML; use framework escaping or trusted types.
|
||||
- Use parameterized queries or prepared statements to block injection.
|
||||
- Keep secrets in secure storage, rotate them regularly, and request least-privilege scopes.
|
||||
- Favor immutable flows and defensive copies for sensitive data.
|
||||
- Use vetted crypto libraries only.
|
||||
- Patch dependencies promptly and monitor advisories.
|
||||
|
||||
## Configuration & Secrets
|
||||
|
||||
- Reach configuration through shared helpers and validate with schemas or dedicated validators.
|
||||
- Handle secrets via the project's secure storage; guard `undefined` and error states.
|
||||
- Document new configuration keys and update related tests.
|
||||
|
||||
## UI & UX Components
|
||||
|
||||
- Sanitize user or external content before rendering.
|
||||
- Keep UI layers thin; push heavy logic to services or state managers.
|
||||
- Use messaging or events to decouple UI from business logic.
|
||||
|
||||
## Testing Expectations
|
||||
|
||||
- Add or update unit tests with the project's framework and naming style.
|
||||
- Expand integration or end-to-end suites when behavior crosses modules or platform APIs.
|
||||
- Run targeted test scripts for quick feedback before submitting.
|
||||
- Avoid brittle timing assertions; prefer fake timers or injected clocks.
|
||||
|
||||
## Performance & Reliability
|
||||
|
||||
- Lazy-load heavy dependencies and dispose them when done.
|
||||
- Defer expensive work until users need it.
|
||||
- Batch or debounce high-frequency events to reduce thrash.
|
||||
- Track resource lifetimes to prevent leaks.
|
||||
|
||||
## Documentation & Comments
|
||||
|
||||
- Add JSDoc to public APIs; include `@remarks` or `@example` when helpful.
|
||||
- Write comments that capture intent, and remove stale notes during refactors.
|
||||
- Update architecture or design docs when introducing significant patterns.
|
||||
404
.github/skills/README.md
vendored
Normal file
404
.github/skills/README.md
vendored
Normal file
@@ -0,0 +1,404 @@
|
||||
# Agent Skills - Charon Project
|
||||
|
||||
This directory contains [Agent Skills](https://agentskills.io) following the agentskills.io specification for AI-discoverable, executable tasks.
|
||||
|
||||
## Overview
|
||||
|
||||
Agent Skills are self-documenting, AI-discoverable task definitions that combine YAML frontmatter (metadata) with Markdown documentation. Each skill represents a specific task or workflow that can be executed by both humans and AI assistants.
|
||||
|
||||
**Location**: `.github/skills/` is the [VS Code Copilot standard location](https://code.visualstudio.com/docs/copilot/customization/agent-skills) for Agent Skills
|
||||
**Format**: Skills follow the [agentskills.io specification](https://agentskills.io/specification) for structure and metadata
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
.github/skills/
|
||||
├── README.md # This file
|
||||
├── scripts/ # Shared infrastructure scripts
|
||||
│ ├── skill-runner.sh # Universal skill executor
|
||||
│ ├── validate-skills.py # Frontmatter validation tool
|
||||
│ ├── _logging_helpers.sh # Logging utilities
|
||||
│ ├── _error_handling_helpers.sh # Error handling utilities
|
||||
│ └── _environment_helpers.sh # Environment validation
|
||||
├── examples/ # Example skill templates
|
||||
└── {skill-name}/ # Individual skill directories
|
||||
├── SKILL.md # Skill definition and documentation
|
||||
└── scripts/
|
||||
└── run.sh # Skill execution script
|
||||
```
|
||||
|
||||
## Available Skills
|
||||
|
||||
### Testing Skills
|
||||
|
||||
| Skill Name | Category | Description | Status |
|
||||
|------------|----------|-------------|--------|
|
||||
| [test-backend-coverage](./test-backend-coverage.SKILL.md) | test | Run Go backend tests with coverage analysis | ✅ Active |
|
||||
| [test-backend-unit](./test-backend-unit.SKILL.md) | test | Run fast Go unit tests without coverage | ✅ Active |
|
||||
| [test-frontend-coverage](./test-frontend-coverage.SKILL.md) | test | Run frontend tests with coverage reporting | ✅ Active |
|
||||
| [test-frontend-unit](./test-frontend-unit.SKILL.md) | test | Run fast frontend unit tests without coverage | ✅ Active |
|
||||
|
||||
### Integration Testing Skills
|
||||
|
||||
| Skill Name | Category | Description | Status |
|
||||
|------------|----------|-------------|--------|
|
||||
| [integration-test-all](./integration-test-all.SKILL.md) | integration | Run all integration tests in sequence | ✅ Active |
|
||||
| [integration-test-coraza](./integration-test-coraza.SKILL.md) | integration | Test Coraza WAF integration | ✅ Active |
|
||||
| [integration-test-crowdsec](./integration-test-crowdsec.SKILL.md) | integration | Test CrowdSec bouncer integration | ✅ Active |
|
||||
| [integration-test-crowdsec-decisions](./integration-test-crowdsec-decisions.SKILL.md) | integration | Test CrowdSec decisions API | ✅ Active |
|
||||
| [integration-test-crowdsec-startup](./integration-test-crowdsec-startup.SKILL.md) | integration | Test CrowdSec startup sequence | ✅ Active |
|
||||
|
||||
### Security Skills
|
||||
|
||||
| Skill Name | Category | Description | Status |
|
||||
|------------|----------|-------------|--------|
|
||||
| [security-scan-trivy](./security-scan-trivy.SKILL.md) | security | Run Trivy vulnerability scanner | ✅ Active |
|
||||
| [security-scan-go-vuln](./security-scan-go-vuln.SKILL.md) | security | Run Go vulnerability check | ✅ Active |
|
||||
|
||||
### QA Skills
|
||||
|
||||
| Skill Name | Category | Description | Status |
|
||||
|------------|----------|-------------|--------|
|
||||
| [qa-precommit-all](./qa-precommit-all.SKILL.md) | qa | Run all pre-commit hooks on entire codebase | ✅ Active |
|
||||
|
||||
### Utility Skills
|
||||
|
||||
| Skill Name | Category | Description | Status |
|
||||
|------------|----------|-------------|--------|
|
||||
| [utility-version-check](./utility-version-check.SKILL.md) | utility | Validate version matches git tag | ✅ Active |
|
||||
| [utility-clear-go-cache](./utility-clear-go-cache.SKILL.md) | utility | Clear Go build and module caches | ✅ Active |
|
||||
| [utility-bump-beta](./utility-bump-beta.SKILL.md) | utility | Increment beta version number | ✅ Active |
|
||||
| [utility-db-recovery](./utility-db-recovery.SKILL.md) | utility | Database integrity check and recovery | ✅ Active |
|
||||
|
||||
### Docker Skills
|
||||
|
||||
| Skill Name | Category | Description | Status |
|
||||
|------------|----------|-------------|--------|
|
||||
| [docker-start-dev](./docker-start-dev.SKILL.md) | docker | Start development Docker Compose environment | ✅ Active |
|
||||
| [docker-stop-dev](./docker-stop-dev.SKILL.md) | docker | Stop development Docker Compose environment | ✅ Active |
|
||||
| [docker-prune](./docker-prune.SKILL.md) | docker | Clean up unused Docker resources | ✅ Active |
|
||||
|
||||
## Usage
|
||||
|
||||
### Running Skills
|
||||
|
||||
Use the universal skill runner to execute any skill:
|
||||
|
||||
```bash
|
||||
# From project root
|
||||
.github/skills/scripts/skill-runner.sh <skill-name> [args...]
|
||||
|
||||
# Example: Run backend coverage tests
|
||||
.github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
### From VS Code Tasks
|
||||
|
||||
Skills are integrated with VS Code tasks (`.vscode/tasks.json`):
|
||||
|
||||
1. Open Command Palette (`Ctrl+Shift+P` or `Cmd+Shift+P`)
|
||||
2. Select `Tasks: Run Task`
|
||||
3. Choose the task (e.g., `Test: Backend with Coverage`)
|
||||
|
||||
### In CI/CD Workflows
|
||||
|
||||
Reference skills in GitHub Actions:
|
||||
|
||||
```yaml
|
||||
- name: Run Backend Tests with Coverage
|
||||
run: .github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
## Validation
|
||||
|
||||
### Validate a Single Skill
|
||||
|
||||
```bash
|
||||
python3 .github/skills/scripts/validate-skills.py --single .github/skills/test-backend-coverage/SKILL.md
|
||||
```
|
||||
|
||||
### Validate All Skills
|
||||
|
||||
```bash
|
||||
python3 .github/skills/scripts/validate-skills.py
|
||||
```
|
||||
|
||||
### Validation Checks
|
||||
|
||||
The validator ensures:
|
||||
- ✅ Required frontmatter fields are present
|
||||
- ✅ Field formats are correct (name, version, description)
|
||||
- ✅ Tags meet minimum/maximum requirements
|
||||
- ✅ Compatibility information is valid
|
||||
- ✅ Custom metadata follows project conventions
|
||||
|
||||
## Creating New Skills
|
||||
|
||||
### 1. Create Skill Directory Structure
|
||||
|
||||
```bash
|
||||
mkdir -p .github/skills/{skill-name}/scripts
|
||||
```
|
||||
|
||||
### 2. Create SKILL.md
|
||||
|
||||
Start with the template structure:
|
||||
|
||||
```markdown
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "skill-name"
|
||||
version: "1.0.0"
|
||||
description: "Brief description (max 120 chars)"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "tag1"
|
||||
- "tag2"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "tool"
|
||||
version: ">=1.0"
|
||||
optional: false
|
||||
metadata:
|
||||
category: "category-name"
|
||||
execution_time: "short|medium|long"
|
||||
risk_level: "low|medium|high"
|
||||
ci_cd_safe: true|false
|
||||
---
|
||||
|
||||
# Skill Name
|
||||
|
||||
## Overview
|
||||
|
||||
Brief description of what this skill does.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- List prerequisites
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh skill-name
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Usage
|
||||
|
||||
```bash
|
||||
# Example command
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: YYYY-MM-DD
|
||||
**Maintained by**: Charon Project
|
||||
```
|
||||
|
||||
### 3. Create Execution Script
|
||||
|
||||
Create `scripts/run.sh` with proper structure:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../../scripts" && pwd)"
|
||||
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
# Add validation calls here
|
||||
|
||||
# Execute skill logic
|
||||
log_step "EXECUTION" "Running skill"
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
# Your skill logic here
|
||||
|
||||
log_success "Skill completed successfully"
|
||||
```
|
||||
|
||||
### 4. Set Permissions
|
||||
|
||||
```bash
|
||||
chmod +x .github/skills/{skill-name}/scripts/run.sh
|
||||
```
|
||||
|
||||
### 5. Validate
|
||||
|
||||
```bash
|
||||
python3 .github/skills/scripts/validate-skills.py --single .github/skills/{skill-name}/SKILL.md
|
||||
```
|
||||
|
||||
### 6. Test
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh {skill-name}
|
||||
```
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- **Skill Names**: `{category}-{feature}-{variant}` (kebab-case)
|
||||
- **Categories**: `test`, `integration-test`, `security`, `qa`, `build`, `utility`, `docker`
|
||||
- **Examples**:
|
||||
- `test-backend-coverage`
|
||||
- `integration-test-crowdsec`
|
||||
- `security-scan-trivy`
|
||||
- `utility-version-check`
|
||||
|
||||
## Best Practices
|
||||
|
||||
### Documentation
|
||||
- Keep SKILL.md under 500 lines
|
||||
- Use progressive disclosure (link to extended docs for complex topics)
|
||||
- Include practical examples
|
||||
- Document all prerequisites and environment variables
|
||||
|
||||
### Scripts
|
||||
- Always source helper scripts for consistent logging and error handling
|
||||
- Validate environment before execution
|
||||
- Use `set -euo pipefail` for robust error handling
|
||||
- Make scripts idempotent when possible
|
||||
- Clean up resources on exit
|
||||
|
||||
### Metadata
|
||||
- Use accurate `execution_time` values for scheduling
|
||||
- Set `ci_cd_safe: false` for skills requiring human oversight
|
||||
- Mark `idempotent: true` only if truly safe to run multiple times
|
||||
- Include all required dependencies in `requirements`
|
||||
|
||||
### Error Handling
|
||||
- Use helper functions (`log_error`, `error_exit`, `check_command_exists`)
|
||||
- Provide clear error messages with remediation steps
|
||||
- Return appropriate exit codes (0 = success, non-zero = failure)
|
||||
|
||||
## Helper Scripts Reference
|
||||
|
||||
### Logging Helpers (`_logging_helpers.sh`)
|
||||
|
||||
```bash
|
||||
log_info "message" # Informational message
|
||||
log_success "message" # Success message (green)
|
||||
log_warning "message" # Warning message (yellow)
|
||||
log_error "message" # Error message (red)
|
||||
log_debug "message" # Debug message (only if DEBUG=1)
|
||||
log_step "STEP" "msg" # Step header
|
||||
log_command "cmd" # Log command before executing
|
||||
```
|
||||
|
||||
### Error Handling Helpers (`_error_handling_helpers.sh`)
|
||||
|
||||
```bash
|
||||
error_exit "message" [exit_code] # Print error and exit
|
||||
check_command_exists "cmd" ["message"] # Verify command exists
|
||||
check_file_exists "file" ["message"] # Verify file exists
|
||||
check_dir_exists "dir" ["message"] # Verify directory exists
|
||||
run_with_retry max_attempts delay cmd... # Retry command with backoff
|
||||
trap_error [script_name] # Set up error trapping
|
||||
cleanup_on_exit cleanup_func # Register cleanup function
|
||||
```
|
||||
|
||||
### Environment Helpers (`_environment_helpers.sh`)
|
||||
|
||||
```bash
|
||||
validate_go_environment ["min_version"] # Check Go installation
|
||||
validate_python_environment ["min_version"] # Check Python installation
|
||||
validate_node_environment ["min_version"] # Check Node.js installation
|
||||
validate_docker_environment # Check Docker installation
|
||||
set_default_env "VAR" "default_value" # Set env var with default
|
||||
validate_project_structure file1 file2... # Check required files exist
|
||||
get_project_root ["marker_file"] # Find project root directory
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not found
|
||||
```
|
||||
Error: Skill not found: skill-name
|
||||
```
|
||||
**Solution**: Verify the skill directory exists in `.github/skills/` and contains a `SKILL.md` file
|
||||
|
||||
### Skill script not executable
|
||||
```
|
||||
Error: Skill execution script is not executable
|
||||
```
|
||||
**Solution**: Run `chmod +x .github/skills/{skill-name}/scripts/run.sh`
|
||||
|
||||
### Validation errors
|
||||
```
|
||||
[ERROR] skill.SKILL.md :: description: Must be 120 characters or less
|
||||
```
|
||||
**Solution**: Fix the frontmatter field according to the error message and re-validate
|
||||
|
||||
### Command not found in skill
|
||||
```
|
||||
Error: go is not installed or not in PATH
|
||||
```
|
||||
**Solution**: Install the required dependency or ensure it's in your PATH
|
||||
|
||||
## Integration Points
|
||||
|
||||
### VS Code Tasks
|
||||
Skills are integrated in `.vscode/tasks.json`:
|
||||
```json
|
||||
{
|
||||
"label": "Test: Backend with Coverage",
|
||||
"type": "shell",
|
||||
"command": ".github/skills/scripts/skill-runner.sh test-backend-coverage",
|
||||
"group": "test"
|
||||
}
|
||||
```
|
||||
|
||||
### GitHub Actions
|
||||
Skills are referenced in `.github/workflows/`:
|
||||
```yaml
|
||||
- name: Run Backend Tests with Coverage
|
||||
run: .github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
### Pre-commit Hooks
|
||||
Skills can be used in `.pre-commit-config.yaml`:
|
||||
```yaml
|
||||
repos:
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: backend-coverage
|
||||
name: Backend Coverage Check
|
||||
entry: .github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
language: system
|
||||
```
|
||||
|
||||
## Resources
|
||||
|
||||
- [agentskills.io Specification](https://agentskills.io/specification)
|
||||
- [VS Code Copilot Agent Skills](https://code.visualstudio.com/docs/copilot/customization/agent-skills)
|
||||
- [Project Documentation](../../docs/)
|
||||
- [Contributing Guide](../../CONTRIBUTING.md)
|
||||
|
||||
## Support
|
||||
|
||||
For issues, questions, or contributions:
|
||||
1. Check existing [GitHub Issues](https://github.com/Wikid82/charon/issues)
|
||||
2. Review [CONTRIBUTING.md](../../CONTRIBUTING.md)
|
||||
3. Create a new issue if needed
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**License**: MIT
|
||||
14
.github/skills/docker-prune-scripts/run.sh
vendored
Executable file
14
.github/skills/docker-prune-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Docker: Prune Unused Resources - Execution Script
|
||||
# ==============================================================================
|
||||
# This script removes unused Docker resources to free up disk space.
|
||||
#
|
||||
# Usage: ./run.sh
|
||||
# Exit codes: 0 = success, non-zero = failure
|
||||
# ==============================================================================
|
||||
|
||||
# Remove unused Docker resources (containers, images, networks, build cache)
|
||||
exec docker system prune -f
|
||||
293
.github/skills/docker-prune.SKILL.md
vendored
Normal file
293
.github/skills/docker-prune.SKILL.md
vendored
Normal file
@@ -0,0 +1,293 @@
|
||||
---
|
||||
name: "docker-prune"
|
||||
version: "1.0.0"
|
||||
description: "Removes unused Docker resources including stopped containers, dangling images, and unused networks"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "docker"
|
||||
- "cleanup"
|
||||
- "maintenance"
|
||||
- "disk-space"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters: []
|
||||
outputs:
|
||||
- name: "exit_code"
|
||||
type: "integer"
|
||||
description: "0 on success, non-zero on failure"
|
||||
- name: "reclaimed_space"
|
||||
type: "string"
|
||||
description: "Amount of disk space freed"
|
||||
metadata:
|
||||
category: "docker"
|
||||
subcategory: "maintenance"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: false
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Docker: Prune Unused Resources
|
||||
|
||||
## Overview
|
||||
|
||||
Removes unused Docker resources to free up disk space and clean up the Docker environment. This includes stopped containers, dangling images, unused networks, and build cache. The operation is safe and only removes resources not currently in use.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Engine installed and running
|
||||
- Sufficient permissions to run Docker commands
|
||||
- No critical containers running (verify first)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
.github/skills/docker-prune-scripts/run.sh
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh docker-prune
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Docker: Prune Unused Resources**
|
||||
|
||||
## Parameters
|
||||
|
||||
This skill uses Docker's default prune behavior (safe mode). No parameters accepted.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
This skill requires no environment variables.
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0
|
||||
- **Error Exit Codes**: Non-zero on failure
|
||||
- **Console Output**: List of removed resources and space reclaimed
|
||||
|
||||
### Output Example
|
||||
|
||||
```
|
||||
Deleted Containers:
|
||||
f8d1234567890abcdef1234567890abcdef1234567890abcdef1234567890ab
|
||||
|
||||
Deleted Networks:
|
||||
charon-test_default
|
||||
old-network_default
|
||||
|
||||
Deleted Images:
|
||||
untagged: myimage@sha256:abcdef1234567890...
|
||||
deleted: sha256:1234567890abcdef...
|
||||
|
||||
Deleted build cache objects:
|
||||
abcd1234
|
||||
efgh5678
|
||||
|
||||
Total reclaimed space: 2.5GB
|
||||
```
|
||||
|
||||
## What Gets Removed
|
||||
|
||||
The `docker system prune -f` command removes:
|
||||
|
||||
1. **Stopped Containers**: Containers not currently running
|
||||
2. **Dangling Images**: Images with no tag (intermediate layers)
|
||||
3. **Unused Networks**: Networks with no connected containers
|
||||
4. **Build Cache**: Cached layers from image builds
|
||||
|
||||
## What Gets Preserved
|
||||
|
||||
This command **DOES NOT** remove:
|
||||
- **Running Containers**: Active containers are untouched
|
||||
- **Tagged Images**: Images with tags are preserved
|
||||
- **Volumes**: Data volumes are never removed
|
||||
- **Used Networks**: Networks with connected containers
|
||||
- **Active Build Cache**: Cache for recent builds
|
||||
|
||||
## Safety Features
|
||||
|
||||
- **Force Flag (`-f`)**: Skips confirmation prompt (safe for automation)
|
||||
- **Safe by Default**: Only removes truly unused resources
|
||||
- **Volume Protection**: Volumes require separate `docker volume prune` command
|
||||
- **Running Container Protection**: Cannot remove active containers
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Regular Cleanup
|
||||
|
||||
```bash
|
||||
# Clean up Docker environment
|
||||
.github/skills/docker-prune-scripts/run.sh
|
||||
```
|
||||
|
||||
### Example 2: Check Disk Usage Before/After
|
||||
|
||||
```bash
|
||||
# Check current usage
|
||||
docker system df
|
||||
|
||||
# Run cleanup
|
||||
.github/skills/docker-prune-scripts/run.sh
|
||||
|
||||
# Verify freed space
|
||||
docker system df
|
||||
```
|
||||
|
||||
### Example 3: Aggressive Cleanup (Manual)
|
||||
|
||||
```bash
|
||||
# Standard prune
|
||||
.github/skills/docker-prune-scripts/run.sh
|
||||
|
||||
# Additionally prune volumes (WARNING: data loss)
|
||||
docker volume prune -f
|
||||
|
||||
# Remove all unused images (not just dangling)
|
||||
docker image prune -a -f
|
||||
```
|
||||
|
||||
## Disk Space Analysis
|
||||
|
||||
Check Docker disk usage:
|
||||
|
||||
```bash
|
||||
# Summary view
|
||||
docker system df
|
||||
|
||||
# Detailed view
|
||||
docker system df -v
|
||||
```
|
||||
|
||||
Output shows:
|
||||
- **Images**: Total size of cached images
|
||||
- **Containers**: Size of container writable layers
|
||||
- **Local Volumes**: Size of data volumes
|
||||
- **Build Cache**: Size of cached build layers
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Disk space is running low
|
||||
- After development cycles (many builds)
|
||||
- After running integration tests
|
||||
- Before system backup/snapshot
|
||||
- As part of regular maintenance
|
||||
- After Docker image experiments
|
||||
|
||||
## Frequency Recommendations
|
||||
|
||||
- **Daily**: For active development machines
|
||||
- **Weekly**: For CI/CD build servers
|
||||
- **Monthly**: For production servers (cautiously)
|
||||
- **On-Demand**: When disk space is low
|
||||
|
||||
## Error Handling
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
### Permission Denied
|
||||
```
|
||||
Error: permission denied
|
||||
```
|
||||
Solution: Add user to docker group or use sudo
|
||||
|
||||
### Daemon Not Running
|
||||
```
|
||||
Error: Cannot connect to Docker daemon
|
||||
```
|
||||
Solution: Start Docker service
|
||||
|
||||
### Resource in Use
|
||||
```
|
||||
Error: resource is in use
|
||||
```
|
||||
This is normal - only unused resources are removed
|
||||
|
||||
## Advanced Cleanup Options
|
||||
|
||||
For more aggressive cleanup:
|
||||
|
||||
### Remove All Unused Images
|
||||
|
||||
```bash
|
||||
docker image prune -a -f
|
||||
```
|
||||
|
||||
### Remove Unused Volumes (DANGER: Data Loss)
|
||||
|
||||
```bash
|
||||
docker volume prune -f
|
||||
```
|
||||
|
||||
### Complete System Prune (DANGER)
|
||||
|
||||
```bash
|
||||
docker system prune -a --volumes -f
|
||||
```
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [docker-stop-dev](./docker-stop-dev.SKILL.md) - Stop containers before cleanup
|
||||
- [docker-start-dev](./docker-start-dev.SKILL.md) - Restart after cleanup
|
||||
- [utility-clear-go-cache](./utility-clear-go-cache.SKILL.md) - Clear Go build cache
|
||||
|
||||
## Notes
|
||||
|
||||
- **Idempotent**: Safe to run multiple times
|
||||
- **Low Risk**: Only removes unused resources
|
||||
- **No Data Loss**: Volumes are protected by default
|
||||
- **Fast Execution**: Typically completes in seconds
|
||||
- **No Network Required**: Local operation only
|
||||
- **Not CI/CD Safe**: Can interfere with parallel builds
|
||||
- **Build Cache**: May slow down next build if cache is cleared
|
||||
|
||||
## Disk Space Recovery
|
||||
|
||||
Typical space recovery by resource type:
|
||||
- **Stopped Containers**: 10-100 MB each
|
||||
- **Dangling Images**: 100 MB - 2 GB total
|
||||
- **Build Cache**: 1-10 GB (if many builds)
|
||||
- **Unused Networks**: Negligible space
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Space Freed
|
||||
|
||||
- Check for running containers: `docker ps`
|
||||
- Verify images are untagged: `docker images -f "dangling=true"`
|
||||
- Check volume usage: `docker volume ls`
|
||||
|
||||
### Space Still Low After Prune
|
||||
|
||||
- Use aggressive pruning (see Advanced Cleanup)
|
||||
- Check non-Docker disk usage: `df -h`
|
||||
- Consider increasing disk allocation
|
||||
|
||||
### Container Won't Be Removed
|
||||
|
||||
- Check if container is running: `docker ps`
|
||||
- Stop container first: `docker stop container_name`
|
||||
- Force removal: `docker rm -f container_name`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Docker Command**: `docker system prune -f`
|
||||
21
.github/skills/docker-start-dev-scripts/run.sh
vendored
Executable file
21
.github/skills/docker-start-dev-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Docker: Start Development Environment - Execution Script
|
||||
# ==============================================================================
|
||||
# This script starts the Docker Compose development environment.
|
||||
#
|
||||
# Usage: ./run.sh
|
||||
# Exit codes: 0 = success, non-zero = failure
|
||||
# ==============================================================================
|
||||
|
||||
# Determine the repository root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Change to repository root
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Start development environment with Docker Compose
|
||||
exec docker compose -f .docker/compose/docker-compose.dev.yml up -d
|
||||
269
.github/skills/docker-start-dev.SKILL.md
vendored
Normal file
269
.github/skills/docker-start-dev.SKILL.md
vendored
Normal file
@@ -0,0 +1,269 @@
|
||||
---
|
||||
name: "docker-start-dev"
|
||||
version: "1.0.0"
|
||||
description: "Starts the Charon development Docker Compose environment with all required services"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "docker"
|
||||
- "development"
|
||||
- "compose"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "docker-compose"
|
||||
version: ">=2.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters: []
|
||||
outputs:
|
||||
- name: "exit_code"
|
||||
type: "integer"
|
||||
description: "0 on success, non-zero on failure"
|
||||
metadata:
|
||||
category: "docker"
|
||||
subcategory: "environment"
|
||||
execution_time: "medium"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: false
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Docker: Start Development Environment
|
||||
|
||||
## Overview
|
||||
|
||||
Starts the Charon development Docker Compose environment in detached mode. This brings up all required services including the application, database, CrowdSec, and any other dependencies defined in `.docker/compose/docker-compose.dev.yml`.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Engine installed and running
|
||||
- Docker Compose V2 installed
|
||||
- `.docker/compose/docker-compose.dev.yml` file in repository
|
||||
- Network access (for pulling images)
|
||||
- Sufficient system resources (CPU, memory, disk)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
.github/skills/docker-start-dev-scripts/run.sh
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh docker-start-dev
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Docker: Start Dev Environment**
|
||||
|
||||
## Parameters
|
||||
|
||||
This skill accepts no parameters. Services are configured in `.docker/compose/docker-compose.dev.yml`.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
This skill uses environment variables defined in:
|
||||
- `.env` (if present)
|
||||
- `.docker/compose/docker-compose.dev.yml` environment section
|
||||
- Shell environment
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 - All services started successfully
|
||||
- **Error Exit Codes**: Non-zero - Service startup failed
|
||||
- **Console Output**: Docker Compose logs and status
|
||||
|
||||
### Output Example
|
||||
|
||||
```
|
||||
[+] Running 5/5
|
||||
✔ Network charon-dev_default Created
|
||||
✔ Container charon-dev-db-1 Started
|
||||
✔ Container charon-dev-crowdsec-1 Started
|
||||
✔ Container charon-dev-app-1 Started
|
||||
✔ Container charon-dev-caddy-1 Started
|
||||
```
|
||||
|
||||
## What Gets Started
|
||||
|
||||
Services defined in `.docker/compose/docker-compose.dev.yml`:
|
||||
1. **charon-app**: Main application container
|
||||
2. **charon-db**: SQLite or PostgreSQL database
|
||||
3. **crowdsec**: Security bouncer
|
||||
4. **caddy**: Reverse proxy (if configured)
|
||||
5. **Other Services**: As defined in compose file
|
||||
|
||||
## Service Startup Order
|
||||
|
||||
Docker Compose respects `depends_on` directives:
|
||||
1. Database services start first
|
||||
2. Security services (CrowdSec) start next
|
||||
3. Application services start after dependencies
|
||||
4. Reverse proxy starts last
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Start Development Environment
|
||||
|
||||
```bash
|
||||
# Start all development services
|
||||
.github/skills/docker-start-dev-scripts/run.sh
|
||||
|
||||
# Verify services are running
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml ps
|
||||
```
|
||||
|
||||
### Example 2: Start and View Logs
|
||||
|
||||
```bash
|
||||
# Start services in detached mode
|
||||
.github/skills/docker-start-dev-scripts/run.sh
|
||||
|
||||
# Follow logs from all services
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml logs -f
|
||||
```
|
||||
|
||||
### Example 3: Start and Test Application
|
||||
|
||||
```bash
|
||||
# Start development environment
|
||||
.github/skills/docker-start-dev-scripts/run.sh
|
||||
|
||||
# Wait for services to be healthy
|
||||
sleep 10
|
||||
|
||||
# Test application endpoint
|
||||
curl http://localhost:8080/health
|
||||
```
|
||||
|
||||
## Service Health Checks
|
||||
|
||||
After starting, verify services are healthy:
|
||||
|
||||
```bash
|
||||
# Check service status
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml ps
|
||||
|
||||
# Check specific service logs
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml logs app
|
||||
|
||||
# Execute command in running container
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml exec app /bin/sh
|
||||
```
|
||||
|
||||
## Port Mappings
|
||||
|
||||
Default development ports (check `.docker/compose/docker-compose.dev.yml`):
|
||||
- **8080**: Application HTTP
|
||||
- **8443**: Application HTTPS (if configured)
|
||||
- **9000**: Admin panel (if configured)
|
||||
- **3000**: Frontend dev server (if configured)
|
||||
|
||||
## Detached Mode
|
||||
|
||||
The `-d` flag runs containers in detached mode:
|
||||
- Services run in background
|
||||
- Terminal is freed for other commands
|
||||
- Use `docker compose logs -f` to view output
|
||||
|
||||
## Error Handling
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
### Port Already in Use
|
||||
```
|
||||
Error: bind: address already in use
|
||||
```
|
||||
Solution: Stop conflicting service or change port in compose file
|
||||
|
||||
### Image Pull Failed
|
||||
```
|
||||
Error: failed to pull image
|
||||
```
|
||||
Solution: Check network connection, authenticate to registry
|
||||
|
||||
### Insufficient Resources
|
||||
```
|
||||
Error: failed to start container
|
||||
```
|
||||
Solution: Free up system resources, stop other containers
|
||||
|
||||
### Configuration Error
|
||||
```
|
||||
Error: invalid compose file
|
||||
```
|
||||
Solution: Validate compose file with `docker compose config`
|
||||
|
||||
## Post-Startup Verification
|
||||
|
||||
After starting, verify:
|
||||
|
||||
1. **All Services Running**:
|
||||
```bash
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml ps
|
||||
```
|
||||
|
||||
2. **Application Accessible**:
|
||||
```bash
|
||||
curl http://localhost:8080/health
|
||||
```
|
||||
|
||||
3. **No Error Logs**:
|
||||
```bash
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml logs --tail=50
|
||||
```
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [docker-stop-dev](./docker-stop-dev.SKILL.md) - Stop development environment
|
||||
- [docker-prune](./docker-prune.SKILL.md) - Clean up Docker resources
|
||||
- [integration-test-all](./integration-test-all.SKILL.md) - Run integration tests
|
||||
|
||||
## Notes
|
||||
|
||||
- **Idempotent**: Safe to run multiple times (recreates only if needed)
|
||||
- **Resource Usage**: Development mode may use more resources than production
|
||||
- **Data Persistence**: Volumes persist data across restarts
|
||||
- **Network Access**: Requires internet for initial image pulls
|
||||
- **Not CI/CD Safe**: Intended for local development only
|
||||
- **Background Execution**: Services run in detached mode
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Services Won't Start
|
||||
|
||||
1. Check Docker daemon: `docker info`
|
||||
2. Validate compose file: `docker compose -f .docker/compose/docker-compose.dev.yml config`
|
||||
3. Check available resources: `docker stats`
|
||||
4. Review logs: `docker compose -f .docker/compose/docker-compose.dev.yml logs`
|
||||
|
||||
### Slow Startup
|
||||
|
||||
- First run pulls images (may take time)
|
||||
- Subsequent runs use cached images
|
||||
- Use `docker compose pull` to pre-pull images
|
||||
|
||||
### Service Dependency Issues
|
||||
|
||||
- Check `depends_on` in compose file
|
||||
- Add healthchecks for critical services
|
||||
- Increase startup timeout if needed
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Compose File**: `.docker/compose/docker-compose.dev.yml`
|
||||
21
.github/skills/docker-stop-dev-scripts/run.sh
vendored
Executable file
21
.github/skills/docker-stop-dev-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,21 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Docker: Stop Development Environment - Execution Script
|
||||
# ==============================================================================
|
||||
# This script stops and removes the Docker Compose development environment.
|
||||
#
|
||||
# Usage: ./run.sh
|
||||
# Exit codes: 0 = success, non-zero = failure
|
||||
# ==============================================================================
|
||||
|
||||
# Determine the repository root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Change to repository root
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Stop development environment with Docker Compose
|
||||
exec docker compose -f .docker/compose/docker-compose.dev.yml down
|
||||
272
.github/skills/docker-stop-dev.SKILL.md
vendored
Normal file
272
.github/skills/docker-stop-dev.SKILL.md
vendored
Normal file
@@ -0,0 +1,272 @@
|
||||
---
|
||||
name: "docker-stop-dev"
|
||||
version: "1.0.0"
|
||||
description: "Stops and removes the Charon development Docker Compose environment and containers"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "docker"
|
||||
- "development"
|
||||
- "compose"
|
||||
- "cleanup"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "docker-compose"
|
||||
version: ">=2.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters: []
|
||||
outputs:
|
||||
- name: "exit_code"
|
||||
type: "integer"
|
||||
description: "0 on success, non-zero on failure"
|
||||
metadata:
|
||||
category: "docker"
|
||||
subcategory: "environment"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: false
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Docker: Stop Development Environment
|
||||
|
||||
## Overview
|
||||
|
||||
Stops and removes all containers defined in the Charon development Docker Compose environment. This gracefully shuts down services, removes containers, and cleans up the default network while preserving volumes and data.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker Engine installed and running
|
||||
- Docker Compose V2 installed
|
||||
- Development environment previously started
|
||||
- `.docker/compose/docker-compose.dev.yml` file in repository
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
.github/skills/docker-stop-dev-scripts/run.sh
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh docker-stop-dev
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Docker: Stop Dev Environment**
|
||||
|
||||
## Parameters
|
||||
|
||||
This skill accepts no parameters.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
This skill requires no environment variables.
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 - All services stopped successfully
|
||||
- **Error Exit Codes**: Non-zero - Service shutdown failed
|
||||
- **Console Output**: Docker Compose shutdown status
|
||||
|
||||
### Output Example
|
||||
|
||||
```
|
||||
[+] Running 5/5
|
||||
✔ Container charon-dev-caddy-1 Removed
|
||||
✔ Container charon-dev-app-1 Removed
|
||||
✔ Container charon-dev-crowdsec-1 Removed
|
||||
✔ Container charon-dev-db-1 Removed
|
||||
✔ Network charon-dev_default Removed
|
||||
```
|
||||
|
||||
## What Gets Stopped
|
||||
|
||||
Services defined in `.docker/compose/docker-compose.dev.yml`:
|
||||
1. **Application Containers**: Charon main app
|
||||
2. **Database Containers**: SQLite/PostgreSQL services
|
||||
3. **Security Services**: CrowdSec bouncer
|
||||
4. **Reverse Proxy**: Caddy server
|
||||
5. **Network**: Default Docker Compose network
|
||||
|
||||
## What Gets Preserved
|
||||
|
||||
The `down` command preserves:
|
||||
- **Volumes**: Database data persists
|
||||
- **Images**: Docker images remain cached
|
||||
- **Configs**: Configuration files unchanged
|
||||
|
||||
To remove volumes, use `docker compose -f .docker/compose/docker-compose.dev.yml down -v`
|
||||
|
||||
## Shutdown Order
|
||||
|
||||
Docker Compose stops services in reverse dependency order:
|
||||
1. Reverse proxy stops first
|
||||
2. Application services stop next
|
||||
3. Security services stop
|
||||
4. Database services stop last
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Stop Development Environment
|
||||
|
||||
```bash
|
||||
# Stop all development services
|
||||
.github/skills/docker-stop-dev-scripts/run.sh
|
||||
|
||||
# Verify services are stopped
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml ps
|
||||
```
|
||||
|
||||
### Example 2: Stop and Remove Volumes
|
||||
|
||||
```bash
|
||||
# Stop services and remove data volumes
|
||||
docker compose -f .docker/compose/docker-compose.dev.yml down -v
|
||||
```
|
||||
|
||||
### Example 3: Stop and Verify Cleanup
|
||||
|
||||
```bash
|
||||
# Stop development environment
|
||||
.github/skills/docker-stop-dev-scripts/run.sh
|
||||
|
||||
# Verify no containers running
|
||||
docker ps --filter "name=charon-dev"
|
||||
|
||||
# Verify network removed
|
||||
docker network ls | grep charon-dev
|
||||
```
|
||||
|
||||
## Graceful Shutdown
|
||||
|
||||
The `down` command:
|
||||
1. Sends `SIGTERM` to each container
|
||||
2. Waits for graceful shutdown (default: 10 seconds)
|
||||
3. Sends `SIGKILL` if timeout exceeded
|
||||
4. Removes stopped containers
|
||||
5. Removes default network
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Switching between development and production modes
|
||||
- Freeing system resources (CPU, memory)
|
||||
- Preparing for system shutdown/restart
|
||||
- Resetting environment for troubleshooting
|
||||
- Applying Docker Compose configuration changes
|
||||
- Before database recovery operations
|
||||
|
||||
## Error Handling
|
||||
|
||||
Common issues and solutions:
|
||||
|
||||
### Container Already Stopped
|
||||
```
|
||||
Warning: Container already stopped
|
||||
```
|
||||
No action needed - idempotent operation
|
||||
|
||||
### Volume in Use
|
||||
```
|
||||
Error: volume is in use
|
||||
```
|
||||
Solution: Check for other containers using the volume
|
||||
|
||||
### Permission Denied
|
||||
```
|
||||
Error: permission denied
|
||||
```
|
||||
Solution: Add user to docker group or use sudo
|
||||
|
||||
## Post-Shutdown Verification
|
||||
|
||||
After stopping, verify:
|
||||
|
||||
1. **No Running Containers**:
|
||||
```bash
|
||||
docker ps --filter "name=charon-dev"
|
||||
```
|
||||
|
||||
2. **Network Removed**:
|
||||
```bash
|
||||
docker network ls | grep charon-dev
|
||||
```
|
||||
|
||||
3. **Volumes Still Exist** (if data preservation intended):
|
||||
```bash
|
||||
docker volume ls | grep charon
|
||||
```
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [docker-start-dev](./docker-start-dev.SKILL.md) - Start development environment
|
||||
- [docker-prune](./docker-prune.SKILL.md) - Clean up Docker resources
|
||||
- [utility-db-recovery](./utility-db-recovery.SKILL.md) - Database recovery
|
||||
|
||||
## Notes
|
||||
|
||||
- **Idempotent**: Safe to run multiple times (no error if already stopped)
|
||||
- **Data Preservation**: Volumes are NOT removed by default
|
||||
- **Fast Execution**: Typically completes in seconds
|
||||
- **No Network Required**: Local operation only
|
||||
- **Not CI/CD Safe**: Intended for local development only
|
||||
- **Graceful Shutdown**: Allows containers to clean up resources
|
||||
|
||||
## Complete Cleanup
|
||||
|
||||
For complete environment reset:
|
||||
|
||||
```bash
|
||||
# Stop and remove containers, networks
|
||||
.github/skills/docker-stop-dev-scripts/run.sh
|
||||
|
||||
# Remove volumes (WARNING: deletes data)
|
||||
docker volume rm $(docker volume ls -q --filter "name=charon")
|
||||
|
||||
# Remove images (optional)
|
||||
docker rmi $(docker images -q "*charon*")
|
||||
|
||||
# Clean up dangling resources
|
||||
.github/skills/docker-prune-scripts/run.sh
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container Won't Stop
|
||||
|
||||
1. Check container logs: `docker compose logs app`
|
||||
2. Force removal: `docker compose kill`
|
||||
3. Manual cleanup: `docker rm -f container_name`
|
||||
|
||||
### Volume Still in Use
|
||||
|
||||
1. List processes: `docker ps -a`
|
||||
2. Check volume usage: `docker volume inspect volume_name`
|
||||
3. Force volume removal: `docker volume rm -f volume_name`
|
||||
|
||||
### Network Can't Be Removed
|
||||
|
||||
1. Check connected containers: `docker network inspect network_name`
|
||||
2. Disconnect containers: `docker network disconnect network_name container_name`
|
||||
3. Retry removal: `docker network rm network_name`
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Compose File**: `.docker/compose/docker-compose.dev.yml`
|
||||
11
.github/skills/integration-test-all-scripts/run.sh
vendored
Executable file
11
.github/skills/integration-test-all-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Integration Test All - Wrapper Script
|
||||
# Executes the comprehensive integration test suite
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Delegate to the existing integration test script
|
||||
exec "${PROJECT_ROOT}/scripts/integration-test.sh" "$@"
|
||||
220
.github/skills/integration-test-all.SKILL.md
vendored
Normal file
220
.github/skills/integration-test-all.SKILL.md
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "integration-test-all"
|
||||
version: "1.0.0"
|
||||
description: "Run all integration tests including WAF, CrowdSec, Cerberus, and rate limiting"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "integration"
|
||||
- "testing"
|
||||
- "docker"
|
||||
- "end-to-end"
|
||||
- "security"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "docker-compose"
|
||||
version: ">=2.0"
|
||||
optional: false
|
||||
- name: "curl"
|
||||
version: ">=7.0"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "DOCKER_BUILDKIT"
|
||||
description: "Enable Docker BuildKit for faster builds"
|
||||
default: "1"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "Aggregated test results from all integration tests"
|
||||
metadata:
|
||||
category: "integration-test"
|
||||
subcategory: "all"
|
||||
execution_time: "long"
|
||||
risk_level: "medium"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Integration Test All
|
||||
|
||||
## Overview
|
||||
|
||||
Executes the complete integration test suite for the Charon project. This skill runs all integration tests including WAF functionality (Coraza), CrowdSec bouncer integration, Cerberus backend protection, and rate limiting. It validates the entire security stack in a containerized environment.
|
||||
|
||||
This is the comprehensive test suite that ensures all components work together correctly before deployment.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0 or higher installed and running
|
||||
- Docker Compose 2.0 or higher
|
||||
- curl 7.0 or higher for API testing
|
||||
- At least 4GB of available RAM for containers
|
||||
- Network access for pulling container images
|
||||
- Docker daemon running with sufficient disk space
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run all integration tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh integration-test-all
|
||||
```
|
||||
|
||||
### Verbose Mode
|
||||
|
||||
Run with detailed output:
|
||||
|
||||
```bash
|
||||
VERBOSE=1 .github/skills/scripts/skill-runner.sh integration-test-all
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions workflows:
|
||||
|
||||
```yaml
|
||||
- name: Run All Integration Tests
|
||||
run: .github/skills/scripts/skill-runner.sh integration-test-all
|
||||
timeout-minutes: 20
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose output |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| DOCKER_BUILDKIT | No | 1 | Enable BuildKit for faster builds |
|
||||
| SKIP_CLEANUP | No | false | Skip container cleanup after tests |
|
||||
| TEST_TIMEOUT | No | 300 | Timeout in seconds for each test |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All integration tests passed
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: One or more tests failed
|
||||
- **2**: Docker environment setup failed
|
||||
- **3**: Container startup timeout
|
||||
- **4**: Network connectivity issues
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
=== Running Integration Test Suite ===
|
||||
✓ Coraza WAF Integration Tests
|
||||
✓ CrowdSec Bouncer Integration Tests
|
||||
✓ CrowdSec Decision API Tests
|
||||
✓ Cerberus Authentication Tests
|
||||
✓ Rate Limiting Tests
|
||||
|
||||
All integration tests passed!
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh integration-test-all
|
||||
```
|
||||
|
||||
### Example 2: Verbose with Custom Timeout
|
||||
|
||||
```bash
|
||||
VERBOSE=1 TEST_TIMEOUT=600 .github/skills/scripts/skill-runner.sh integration-test-all
|
||||
```
|
||||
|
||||
### Example 3: Skip Cleanup for Debugging
|
||||
|
||||
```bash
|
||||
SKIP_CLEANUP=true .github/skills/scripts/skill-runner.sh integration-test-all
|
||||
```
|
||||
|
||||
### Example 4: CI/CD Pipeline
|
||||
|
||||
```bash
|
||||
# Run with specific Docker configuration
|
||||
DOCKER_BUILDKIT=1 .github/skills/scripts/skill-runner.sh integration-test-all
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
This skill executes the following test suites:
|
||||
|
||||
1. **Coraza WAF Tests**: SQL injection, XSS, path traversal detection
|
||||
2. **CrowdSec Bouncer Tests**: IP blocking, decision synchronization
|
||||
3. **CrowdSec Decision Tests**: Decision creation, removal, persistence
|
||||
4. **Cerberus Tests**: Authentication, authorization, token management
|
||||
5. **Rate Limit Tests**: Request throttling, burst handling
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: Cannot connect to Docker daemon
|
||||
**Solution**: Ensure Docker is running: `sudo systemctl start docker`
|
||||
|
||||
#### Error: Port already in use
|
||||
**Solution**: Stop conflicting services or run cleanup: `docker compose down`
|
||||
|
||||
#### Error: Container startup timeout
|
||||
**Solution**: Check Docker logs: `docker compose logs`
|
||||
|
||||
#### Error: Network connectivity issues
|
||||
**Solution**: Verify network configuration: `docker network ls`
|
||||
|
||||
### Troubleshooting
|
||||
|
||||
- **Slow execution**: Check available system resources
|
||||
- **Random failures**: Increase TEST_TIMEOUT
|
||||
- **Cleanup issues**: Manually run `docker compose down -v`
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [integration-test-coraza](./integration-test-coraza.SKILL.md) - Coraza WAF tests only
|
||||
- [integration-test-crowdsec](./integration-test-crowdsec.SKILL.md) - CrowdSec tests only
|
||||
- [integration-test-crowdsec-decisions](./integration-test-crowdsec-decisions.SKILL.md) - Decision API tests
|
||||
- [integration-test-crowdsec-startup](./integration-test-crowdsec-startup.SKILL.md) - Startup tests
|
||||
- [docker-verify-crowdsec-config](./docker-verify-crowdsec-config.SKILL.md) - Config validation
|
||||
|
||||
## Notes
|
||||
|
||||
- **Execution Time**: Long execution (10-15 minutes typical)
|
||||
- **Resource Intensive**: Requires significant CPU and memory
|
||||
- **Network Required**: Pulls Docker images and tests network functionality
|
||||
- **Idempotency**: Safe to run multiple times (cleanup between runs)
|
||||
- **Cleanup**: Automatically cleans up containers unless SKIP_CLEANUP=true
|
||||
- **CI/CD**: Designed for automated pipelines with proper timeout configuration
|
||||
- **Isolation**: Tests run in isolated Docker networks
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/integration-test.sh`
|
||||
11
.github/skills/integration-test-coraza-scripts/run.sh
vendored
Executable file
11
.github/skills/integration-test-coraza-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Integration Test Coraza - Wrapper Script
|
||||
# Tests Coraza WAF integration
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Delegate to the existing Coraza integration test script
|
||||
exec "${PROJECT_ROOT}/scripts/coraza_integration.sh" "$@"
|
||||
205
.github/skills/integration-test-coraza.SKILL.md
vendored
Normal file
205
.github/skills/integration-test-coraza.SKILL.md
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "integration-test-coraza"
|
||||
version: "1.0.0"
|
||||
description: "Test Coraza WAF integration with OWASP Core Rule Set protection"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "integration"
|
||||
- "waf"
|
||||
- "security"
|
||||
- "coraza"
|
||||
- "owasp"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "curl"
|
||||
version: ">=7.0"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "WAF_ENABLED"
|
||||
description: "Enable WAF protection"
|
||||
default: "true"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "WAF test results including blocked attacks"
|
||||
metadata:
|
||||
category: "integration-test"
|
||||
subcategory: "waf"
|
||||
execution_time: "medium"
|
||||
risk_level: "medium"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Integration Test Coraza
|
||||
|
||||
## Overview
|
||||
|
||||
Tests the Coraza Web Application Firewall (WAF) integration with OWASP Core Rule Set (CRS). This skill validates that the WAF correctly detects and blocks common web attacks including SQL injection, cross-site scripting (XSS), remote code execution (RCE), and path traversal attempts.
|
||||
|
||||
Coraza provides ModSecurity-compatible rule processing with improved performance and modern Go implementation.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0 or higher installed and running
|
||||
- curl 7.0 or higher for HTTP testing
|
||||
- Running Charon Docker environment (or automatic startup)
|
||||
- Network access to test endpoints
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run Coraza WAF integration tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh integration-test-coraza
|
||||
```
|
||||
|
||||
### Verbose Mode
|
||||
|
||||
Run with detailed attack payloads and responses:
|
||||
|
||||
```bash
|
||||
VERBOSE=1 .github/skills/scripts/skill-runner.sh integration-test-coraza
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions workflows:
|
||||
|
||||
```yaml
|
||||
- name: Test Coraza WAF Integration
|
||||
run: .github/skills/scripts/skill-runner.sh integration-test-coraza
|
||||
timeout-minutes: 5
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose output |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| WAF_ENABLED | No | true | Enable WAF protection for tests |
|
||||
| TEST_HOST | No | localhost:8080 | Target host for WAF tests |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All WAF tests passed (attacks blocked correctly)
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: One or more attacks were not blocked
|
||||
- **2**: Docker environment setup failed
|
||||
- **3**: WAF not responding or misconfigured
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
=== Testing Coraza WAF Integration ===
|
||||
✓ SQL Injection: Blocked (403 Forbidden)
|
||||
✓ XSS Attack: Blocked (403 Forbidden)
|
||||
✓ Path Traversal: Blocked (403 Forbidden)
|
||||
✓ RCE Attempt: Blocked (403 Forbidden)
|
||||
✓ Legitimate Request: Allowed (200 OK)
|
||||
|
||||
All Coraza WAF tests passed!
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
This skill validates protection against:
|
||||
|
||||
1. **SQL Injection**: `' OR '1'='1`, `UNION SELECT`, `'; DROP TABLE`
|
||||
2. **Cross-Site Scripting (XSS)**: `<script>alert('XSS')</script>`, `javascript:alert(1)`
|
||||
3. **Path Traversal**: `../../etc/passwd`, `....//....//etc/passwd`
|
||||
4. **Remote Code Execution**: `<?php system($_GET['cmd']); ?>`, `eval()`
|
||||
5. **Legitimate Traffic**: Ensures normal requests are not blocked
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh integration-test-coraza
|
||||
```
|
||||
|
||||
### Example 2: Verbose with Custom Host
|
||||
|
||||
```bash
|
||||
TEST_HOST=production.example.com VERBOSE=1 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-coraza
|
||||
```
|
||||
|
||||
### Example 3: Disable WAF for Comparison
|
||||
|
||||
```bash
|
||||
WAF_ENABLED=false .github/skills/scripts/skill-runner.sh integration-test-coraza
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: WAF not responding
|
||||
**Solution**: Verify Docker containers are running: `docker ps | grep coraza`
|
||||
|
||||
#### Error: Attacks not blocked (false negatives)
|
||||
**Solution**: Check WAF configuration in `configs/coraza/` and rule sets
|
||||
|
||||
#### Error: Legitimate requests blocked (false positives)
|
||||
**Solution**: Review WAF logs and adjust rule sensitivity
|
||||
|
||||
#### Error: Connection refused
|
||||
**Solution**: Ensure application is accessible: `curl http://localhost:8080/health`
|
||||
|
||||
### Debugging
|
||||
|
||||
- **WAF Logs**: `docker logs $(docker ps -q -f name=coraza)`
|
||||
- **Rule Debugging**: Set `SecRuleEngine DetectionOnly` in config
|
||||
- **Test Individual Payloads**: Use curl with specific attack strings
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [integration-test-all](./integration-test-all.SKILL.md) - Complete integration suite
|
||||
- [integration-test-waf](./integration-test-waf.SKILL.md) - General WAF tests
|
||||
- [security-scan-trivy](./security-scan-trivy.SKILL.md) - Vulnerability scanning
|
||||
|
||||
## Notes
|
||||
|
||||
- **OWASP CRS**: Uses Core Rule Set v4.0+ for comprehensive protection
|
||||
- **Execution Time**: Medium execution (3-5 minutes)
|
||||
- **False Positives**: Tuning required for production workloads
|
||||
- **Performance**: Minimal latency impact (<5ms per request)
|
||||
- **Compliance**: Helps meet OWASP Top 10 and PCI DSS requirements
|
||||
- **Logging**: All blocked requests are logged for analysis
|
||||
- **Rule Updates**: Regularly update CRS for latest threat intelligence
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/coraza_integration.sh`
|
||||
11
.github/skills/integration-test-crowdsec-decisions-scripts/run.sh
vendored
Executable file
11
.github/skills/integration-test-crowdsec-decisions-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Integration Test CrowdSec Decisions - Wrapper Script
|
||||
# Tests CrowdSec decision API functionality
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Delegate to the existing CrowdSec decision integration test script
|
||||
exec "${PROJECT_ROOT}/scripts/crowdsec_decision_integration.sh" "$@"
|
||||
252
.github/skills/integration-test-crowdsec-decisions.SKILL.md
vendored
Normal file
252
.github/skills/integration-test-crowdsec-decisions.SKILL.md
vendored
Normal file
@@ -0,0 +1,252 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "integration-test-crowdsec-decisions"
|
||||
version: "1.0.0"
|
||||
description: "Test CrowdSec decision API for creating, retrieving, and removing IP blocks"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "integration"
|
||||
- "crowdsec"
|
||||
- "decisions"
|
||||
- "api"
|
||||
- "blocking"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "curl"
|
||||
version: ">=7.0"
|
||||
optional: false
|
||||
- name: "jq"
|
||||
version: ">=1.6"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "CROWDSEC_API_KEY"
|
||||
description: "CrowdSec API key for decision management"
|
||||
default: "auto-generated"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "Decision API test results"
|
||||
metadata:
|
||||
category: "integration-test"
|
||||
subcategory: "api"
|
||||
execution_time: "medium"
|
||||
risk_level: "medium"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Integration Test CrowdSec Decisions
|
||||
|
||||
## Overview
|
||||
|
||||
Tests the CrowdSec decision API functionality for managing IP block decisions. This skill validates decision creation, retrieval, persistence, expiration, and removal through the CrowdSec Local API (LAPI). It ensures the decision lifecycle works correctly and that bouncers receive updates in real-time.
|
||||
|
||||
Decisions are the core mechanism CrowdSec uses to communicate threats between detectors and enforcers.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0 or higher installed and running
|
||||
- curl 7.0 or higher for API testing
|
||||
- jq 1.6 or higher for JSON parsing
|
||||
- Running CrowdSec LAPI container
|
||||
- Valid CrowdSec API credentials
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run CrowdSec decision API tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
```
|
||||
|
||||
### Verbose Mode
|
||||
|
||||
Run with detailed API request/response logging:
|
||||
|
||||
```bash
|
||||
VERBOSE=1 .github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions workflows:
|
||||
|
||||
```yaml
|
||||
- name: Test CrowdSec Decision API
|
||||
run: .github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
timeout-minutes: 5
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose output |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| CROWDSEC_API_KEY | No | auto | API key for LAPI access |
|
||||
| CROWDSEC_LAPI_URL | No | http://crowdsec:8080 | CrowdSec LAPI endpoint |
|
||||
| TEST_IP | No | 192.0.2.1 | Test IP address for decisions |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All decision API tests passed
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: One or more tests failed
|
||||
- **2**: LAPI not accessible
|
||||
- **3**: Authentication failed
|
||||
- **4**: Decision creation/deletion failed
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
=== Testing CrowdSec Decision API ===
|
||||
✓ Create Decision: IP 192.0.2.1 blocked for 4h
|
||||
✓ Retrieve Decisions: 1 active decision found
|
||||
✓ Decision Details: Correct scope, value, duration
|
||||
✓ Decision Persistence: Survives bouncer restart
|
||||
✓ Decision Expiration: Expires after duration
|
||||
✓ Remove Decision: Successfully deleted
|
||||
✓ Decision Cleanup: No orphaned decisions
|
||||
|
||||
All CrowdSec decision API tests passed!
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
This skill validates:
|
||||
|
||||
1. **Decision Creation**:
|
||||
- Create IP ban decision via API
|
||||
- Create range ban decision
|
||||
- Create captcha decision
|
||||
- Set custom duration and reason
|
||||
|
||||
2. **Decision Retrieval**:
|
||||
- List all active decisions
|
||||
- Filter by scope (ip, range, country)
|
||||
- Filter by value (specific IP)
|
||||
- Pagination support
|
||||
|
||||
3. **Decision Persistence**:
|
||||
- Decisions survive LAPI restart
|
||||
- Decisions sync to bouncers
|
||||
- Database integrity
|
||||
|
||||
4. **Decision Lifecycle**:
|
||||
- Expiration after duration
|
||||
- Manual removal via API
|
||||
- Automatic cleanup of expired decisions
|
||||
|
||||
5. **Decision Synchronization**:
|
||||
- Bouncer receives new decisions
|
||||
- Bouncer updates on decision changes
|
||||
- Real-time propagation
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
```
|
||||
|
||||
### Example 2: Test Specific IP
|
||||
|
||||
```bash
|
||||
TEST_IP=10.0.0.1 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
```
|
||||
|
||||
### Example 3: Custom LAPI URL
|
||||
|
||||
```bash
|
||||
CROWDSEC_LAPI_URL=https://crowdsec-lapi.example.com \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
```
|
||||
|
||||
### Example 4: Verbose with API Key
|
||||
|
||||
```bash
|
||||
CROWDSEC_API_KEY=my-api-key VERBOSE=1 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-decisions
|
||||
```
|
||||
|
||||
## API Endpoints Tested
|
||||
|
||||
- `POST /v1/decisions` - Create new decision
|
||||
- `GET /v1/decisions` - List decisions
|
||||
- `GET /v1/decisions/:id` - Get decision details
|
||||
- `DELETE /v1/decisions/:id` - Remove decision
|
||||
- `GET /v1/decisions/stream` - Bouncer decision stream
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: LAPI not responding
|
||||
**Solution**: Check LAPI container: `docker ps | grep crowdsec`
|
||||
|
||||
#### Error: Authentication failed
|
||||
**Solution**: Verify API key: `docker exec crowdsec cscli machines list`
|
||||
|
||||
#### Error: Decision not created
|
||||
**Solution**: Check LAPI logs for validation errors
|
||||
|
||||
#### Error: Decision not found after creation
|
||||
**Solution**: Verify database connectivity and permissions
|
||||
|
||||
### Debugging
|
||||
|
||||
- **LAPI Logs**: `docker logs $(docker ps -q -f name=crowdsec)`
|
||||
- **Database**: `docker exec crowdsec cscli decisions list`
|
||||
- **API Testing**: `curl -H "X-Api-Key: $KEY" http://localhost:8080/v1/decisions`
|
||||
- **Decision Details**: `docker exec crowdsec cscli decisions list -o json | jq`
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [integration-test-crowdsec](./integration-test-crowdsec.SKILL.md) - Main bouncer tests
|
||||
- [integration-test-crowdsec-startup](./integration-test-crowdsec-startup.SKILL.md) - Startup tests
|
||||
- [integration-test-all](./integration-test-all.SKILL.md) - Complete suite
|
||||
|
||||
## Notes
|
||||
|
||||
- **Execution Time**: Medium execution (3-5 minutes)
|
||||
- **Decision Types**: Supports ban, captcha, and throttle decisions
|
||||
- **Scopes**: IP, range, country, AS, user
|
||||
- **Duration**: From seconds to permanent bans
|
||||
- **API Version**: Tests LAPI v1 endpoints
|
||||
- **Cleanup**: All test decisions are removed after execution
|
||||
- **Idempotency**: Safe to run multiple times
|
||||
- **Isolation**: Uses test IP ranges (RFC 5737)
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/crowdsec_decision_integration.sh`
|
||||
11
.github/skills/integration-test-crowdsec-scripts/run.sh
vendored
Executable file
11
.github/skills/integration-test-crowdsec-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Integration Test CrowdSec - Wrapper Script
|
||||
# Tests CrowdSec bouncer integration
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Delegate to the existing CrowdSec integration test script
|
||||
exec "${PROJECT_ROOT}/scripts/crowdsec_integration.sh" "$@"
|
||||
11
.github/skills/integration-test-crowdsec-startup-scripts/run.sh
vendored
Executable file
11
.github/skills/integration-test-crowdsec-startup-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Integration Test CrowdSec Startup - Wrapper Script
|
||||
# Tests CrowdSec startup sequence and initialization
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Delegate to the existing CrowdSec startup test script
|
||||
exec "${PROJECT_ROOT}/scripts/crowdsec_startup_test.sh" "$@"
|
||||
275
.github/skills/integration-test-crowdsec-startup.SKILL.md
vendored
Normal file
275
.github/skills/integration-test-crowdsec-startup.SKILL.md
vendored
Normal file
@@ -0,0 +1,275 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "integration-test-crowdsec-startup"
|
||||
version: "1.0.0"
|
||||
description: "Test CrowdSec startup sequence, initialization, and error handling"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "integration"
|
||||
- "crowdsec"
|
||||
- "startup"
|
||||
- "initialization"
|
||||
- "resilience"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "curl"
|
||||
version: ">=7.0"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "STARTUP_TIMEOUT"
|
||||
description: "Maximum wait time for startup in seconds"
|
||||
default: "60"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "Startup test results"
|
||||
metadata:
|
||||
category: "integration-test"
|
||||
subcategory: "startup"
|
||||
execution_time: "medium"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Integration Test CrowdSec Startup
|
||||
|
||||
## Overview
|
||||
|
||||
Tests the CrowdSec startup sequence and initialization process. This skill validates that CrowdSec components (LAPI, bouncer) start correctly, handle initialization errors gracefully, and recover from common startup failures. It ensures the system is resilient to network issues, configuration problems, and timing-related edge cases.
|
||||
|
||||
Proper startup behavior is critical for production deployments and automated container orchestration.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0 or higher installed and running
|
||||
- curl 7.0 or higher for health checks
|
||||
- Docker Compose for orchestration
|
||||
- Network connectivity for pulling images
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run CrowdSec startup tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
### Verbose Mode
|
||||
|
||||
Run with detailed startup logging:
|
||||
|
||||
```bash
|
||||
VERBOSE=1 .github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
### Custom Timeout
|
||||
|
||||
Run with extended startup timeout:
|
||||
|
||||
```bash
|
||||
STARTUP_TIMEOUT=120 .github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions workflows:
|
||||
|
||||
```yaml
|
||||
- name: Test CrowdSec Startup
|
||||
run: .github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
timeout-minutes: 5
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose output |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| STARTUP_TIMEOUT | No | 60 | Maximum wait for startup (seconds) |
|
||||
| SKIP_CLEANUP | No | false | Skip container cleanup after tests |
|
||||
| CROWDSEC_VERSION | No | latest | CrowdSec image version to test |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All startup tests passed
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: One or more tests failed
|
||||
- **2**: Startup timeout exceeded
|
||||
- **3**: Configuration errors detected
|
||||
- **4**: Health check failed
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
=== Testing CrowdSec Startup Sequence ===
|
||||
✓ LAPI Initialization: Ready in 8s
|
||||
✓ Database Migration: Successful
|
||||
✓ Bouncer Registration: Successful
|
||||
✓ Configuration Validation: No errors
|
||||
✓ Health Check: All services healthy
|
||||
✓ Graceful Shutdown: Clean exit
|
||||
✓ Restart Resilience: Fast recovery
|
||||
|
||||
All CrowdSec startup tests passed!
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
This skill validates:
|
||||
|
||||
1. **Clean Startup**:
|
||||
- LAPI starts and becomes ready
|
||||
- Database schema migration
|
||||
- Configuration loading
|
||||
- API endpoint availability
|
||||
|
||||
2. **Bouncer Initialization**:
|
||||
- Bouncer registers with LAPI
|
||||
- API key generation/validation
|
||||
- Decision cache initialization
|
||||
- First sync successful
|
||||
|
||||
3. **Error Handling**:
|
||||
- Invalid configuration detection
|
||||
- Missing database handling
|
||||
- Network timeout recovery
|
||||
- Retry mechanisms
|
||||
|
||||
4. **Edge Cases**:
|
||||
- LAPI not ready on first attempt
|
||||
- Race conditions in initialization
|
||||
- Concurrent bouncer registrations
|
||||
- Configuration hot-reload
|
||||
|
||||
5. **Resilience**:
|
||||
- Graceful shutdown
|
||||
- Fast restart (warm start)
|
||||
- State persistence
|
||||
- No resource leaks
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
### Example 2: Extended Timeout
|
||||
|
||||
```bash
|
||||
STARTUP_TIMEOUT=180 VERBOSE=1 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
### Example 3: Test Specific Version
|
||||
|
||||
```bash
|
||||
CROWDSEC_VERSION=v1.5.0 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
### Example 4: Keep Containers for Debugging
|
||||
|
||||
```bash
|
||||
SKIP_CLEANUP=true \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec-startup
|
||||
```
|
||||
|
||||
## Startup Sequence Verified
|
||||
|
||||
1. **Phase 1: Container Start** (0-5s)
|
||||
- Container created and started
|
||||
- Entrypoint script execution
|
||||
- Environment variable processing
|
||||
|
||||
2. **Phase 2: LAPI Initialization** (5-15s)
|
||||
- Database connection established
|
||||
- Schema migration/validation
|
||||
- Configuration parsing
|
||||
- API server binding
|
||||
|
||||
3. **Phase 3: Bouncer Registration** (15-25s)
|
||||
- Bouncer discovers LAPI
|
||||
- API key generated/validated
|
||||
- Initial decision sync
|
||||
- Cache population
|
||||
|
||||
4. **Phase 4: Ready State** (25-30s)
|
||||
- Health check endpoint responds
|
||||
- All components initialized
|
||||
- Ready to process requests
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: Startup timeout exceeded
|
||||
**Solution**: Increase STARTUP_TIMEOUT or check container logs for hangs
|
||||
|
||||
#### Error: Database connection failed
|
||||
**Solution**: Verify database container is running and accessible
|
||||
|
||||
#### Error: Configuration validation failed
|
||||
**Solution**: Check CrowdSec config files for syntax errors
|
||||
|
||||
#### Error: Port already in use
|
||||
**Solution**: Stop conflicting services or change port configuration
|
||||
|
||||
### Debugging
|
||||
|
||||
- **LAPI Logs**: `docker logs $(docker ps -q -f name=crowdsec) -f`
|
||||
- **Bouncer Logs**: `docker logs $(docker ps -q -f name=charon-app) | grep crowdsec`
|
||||
- **Health Check**: `curl http://localhost:8080/health`
|
||||
- **Database**: `docker exec crowdsec cscli machines list`
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [integration-test-crowdsec](./integration-test-crowdsec.SKILL.md) - Main bouncer tests
|
||||
- [integration-test-crowdsec-decisions](./integration-test-crowdsec-decisions.SKILL.md) - Decision tests
|
||||
- [docker-verify-crowdsec-config](./docker-verify-crowdsec-config.SKILL.md) - Config validation
|
||||
|
||||
## Notes
|
||||
|
||||
- **Execution Time**: Medium execution (3-5 minutes)
|
||||
- **Typical Startup**: 20-30 seconds for clean start
|
||||
- **Warm Start**: 5-10 seconds after restart
|
||||
- **Timeout Buffer**: Default timeout includes safety margin
|
||||
- **Container Orchestration**: Tests applicable to Kubernetes/Docker Swarm
|
||||
- **Production Ready**: Validates production deployment scenarios
|
||||
- **Cleanup**: Automatically removes test containers unless SKIP_CLEANUP=true
|
||||
- **Idempotency**: Safe to run multiple times consecutively
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/crowdsec_startup_test.sh`
|
||||
220
.github/skills/integration-test-crowdsec.SKILL.md
vendored
Normal file
220
.github/skills/integration-test-crowdsec.SKILL.md
vendored
Normal file
@@ -0,0 +1,220 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "integration-test-crowdsec"
|
||||
version: "1.0.0"
|
||||
description: "Test CrowdSec bouncer integration and IP blocking functionality"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "integration"
|
||||
- "security"
|
||||
- "crowdsec"
|
||||
- "ip-blocking"
|
||||
- "bouncer"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
- name: "curl"
|
||||
version: ">=7.0"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "CROWDSEC_API_KEY"
|
||||
description: "CrowdSec API key for bouncer authentication"
|
||||
default: "auto-generated"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "CrowdSec integration test results"
|
||||
metadata:
|
||||
category: "integration-test"
|
||||
subcategory: "security"
|
||||
execution_time: "medium"
|
||||
risk_level: "medium"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Integration Test CrowdSec
|
||||
|
||||
## Overview
|
||||
|
||||
Tests the CrowdSec bouncer integration for IP-based threat detection and blocking. This skill validates that the CrowdSec bouncer correctly synchronizes with the CrowdSec Local API (LAPI), retrieves and applies IP block decisions, and enforces security policies.
|
||||
|
||||
CrowdSec provides collaborative security with real-time threat intelligence sharing across the community.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0 or higher installed and running
|
||||
- curl 7.0 or higher for API testing
|
||||
- Running CrowdSec LAPI container
|
||||
- Running Charon application with CrowdSec bouncer enabled
|
||||
- Network access between bouncer and LAPI
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run CrowdSec bouncer integration tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
```
|
||||
|
||||
### Verbose Mode
|
||||
|
||||
Run with detailed API interactions:
|
||||
|
||||
```bash
|
||||
VERBOSE=1 .github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions workflows:
|
||||
|
||||
```yaml
|
||||
- name: Test CrowdSec Integration
|
||||
run: .github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
timeout-minutes: 7
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose output |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| CROWDSEC_API_KEY | No | auto | Bouncer API key (auto-generated if not set) |
|
||||
| CROWDSEC_LAPI_URL | No | http://crowdsec:8080 | CrowdSec LAPI endpoint |
|
||||
| BOUNCER_SYNC_INTERVAL | No | 60 | Decision sync interval in seconds |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All CrowdSec integration tests passed
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: One or more tests failed
|
||||
- **2**: CrowdSec LAPI not accessible
|
||||
- **3**: Bouncer authentication failed
|
||||
- **4**: Decision synchronization failed
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
=== Testing CrowdSec Bouncer Integration ===
|
||||
✓ LAPI Connection: Successful
|
||||
✓ Bouncer Authentication: Valid API Key
|
||||
✓ Decision Retrieval: 5 active decisions
|
||||
✓ IP Blocking: Blocked malicious IP (403 Forbidden)
|
||||
✓ Legitimate IP: Allowed (200 OK)
|
||||
✓ Decision Synchronization: Every 60s
|
||||
|
||||
All CrowdSec integration tests passed!
|
||||
```
|
||||
|
||||
## Test Coverage
|
||||
|
||||
This skill validates:
|
||||
|
||||
1. **LAPI Connectivity**: Bouncer can reach CrowdSec Local API
|
||||
2. **Authentication**: Valid API key and successful bouncer registration
|
||||
3. **Decision Retrieval**: Fetching active IP block decisions
|
||||
4. **IP Blocking**: Correctly blocking malicious IPs
|
||||
5. **Legitimate Traffic**: Allowing non-blocked IPs
|
||||
6. **Decision Synchronization**: Regular updates from LAPI
|
||||
7. **Graceful Degradation**: Handling LAPI downtime
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
```
|
||||
|
||||
### Example 2: Custom API Key
|
||||
|
||||
```bash
|
||||
CROWDSEC_API_KEY=my-bouncer-key \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
```
|
||||
|
||||
### Example 3: Custom LAPI URL
|
||||
|
||||
```bash
|
||||
CROWDSEC_LAPI_URL=http://crowdsec-lapi:8080 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
```
|
||||
|
||||
### Example 4: Fast Sync Interval
|
||||
|
||||
```bash
|
||||
BOUNCER_SYNC_INTERVAL=30 VERBOSE=1 \
|
||||
.github/skills/scripts/skill-runner.sh integration-test-crowdsec
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: Cannot connect to LAPI
|
||||
**Solution**: Verify LAPI container is running: `docker ps | grep crowdsec`
|
||||
|
||||
#### Error: Authentication failed
|
||||
**Solution**: Check API key is valid: `docker exec crowdsec cscli bouncers list`
|
||||
|
||||
#### Error: No decisions retrieved
|
||||
**Solution**: Create test decisions: `docker exec crowdsec cscli decisions add --ip 1.2.3.4`
|
||||
|
||||
#### Error: Blocking not working
|
||||
**Solution**: Check bouncer logs: `docker logs charon-app | grep crowdsec`
|
||||
|
||||
### Debugging
|
||||
|
||||
- **LAPI Logs**: `docker logs $(docker ps -q -f name=crowdsec)`
|
||||
- **Bouncer Status**: Check application logs for sync errors
|
||||
- **Decision List**: `docker exec crowdsec cscli decisions list`
|
||||
- **Test Block**: `curl -H "X-Forwarded-For: 1.2.3.4" http://localhost:8080/`
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [integration-test-crowdsec-decisions](./integration-test-crowdsec-decisions.SKILL.md) - Decision API tests
|
||||
- [integration-test-crowdsec-startup](./integration-test-crowdsec-startup.SKILL.md) - Startup tests
|
||||
- [integration-test-all](./integration-test-all.SKILL.md) - Complete test suite
|
||||
|
||||
## Notes
|
||||
|
||||
- **Execution Time**: Medium execution (4-6 minutes)
|
||||
- **Community Intelligence**: Benefits from CrowdSec's global threat network
|
||||
- **Performance**: Minimal latency with in-memory decision caching
|
||||
- **Scalability**: Tested with thousands of concurrent decisions
|
||||
- **Resilience**: Continues working if LAPI is temporarily unavailable
|
||||
- **Observability**: Full metrics exposed for Prometheus/Grafana
|
||||
- **Compliance**: Supports GDPR-compliant threat intelligence
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/crowdsec_integration.sh`
|
||||
96
.github/skills/qa-precommit-all-scripts/run.sh
vendored
Executable file
96
.github/skills/qa-precommit-all-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
# QA Pre-commit All - Execution Script
|
||||
#
|
||||
# This script runs all pre-commit hooks for comprehensive code quality validation.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_python_environment "3.8" || error_exit "Python 3.8+ is required"
|
||||
|
||||
# Check for virtual environment
|
||||
if [[ -z "${VIRTUAL_ENV:-}" ]]; then
|
||||
log_warning "Virtual environment not activated, attempting to activate .venv"
|
||||
if [[ -f "${PROJECT_ROOT}/.venv/bin/activate" ]]; then
|
||||
# shellcheck source=/dev/null
|
||||
source "${PROJECT_ROOT}/.venv/bin/activate"
|
||||
log_info "Activated virtual environment: ${VIRTUAL_ENV}"
|
||||
else
|
||||
error_exit "Virtual environment not found at ${PROJECT_ROOT}/.venv"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for pre-commit
|
||||
if ! command -v pre-commit &> /dev/null; then
|
||||
error_exit "pre-commit not found. Install with: pip install pre-commit"
|
||||
fi
|
||||
|
||||
# Parse arguments
|
||||
FILES_MODE="${1:---all-files}"
|
||||
|
||||
# Validate files mode
|
||||
case "${FILES_MODE}" in
|
||||
--all-files|staged)
|
||||
;;
|
||||
*)
|
||||
# If not a recognized mode, treat as a specific hook ID
|
||||
HOOK_ID="${FILES_MODE}"
|
||||
FILES_MODE="--all-files"
|
||||
log_info "Running specific hook: ${HOOK_ID}"
|
||||
;;
|
||||
esac
|
||||
|
||||
# Change to project root
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
# Execute pre-commit
|
||||
log_step "VALIDATION" "Running pre-commit hooks"
|
||||
log_info "Files mode: ${FILES_MODE}"
|
||||
|
||||
if [[ -n "${SKIP:-}" ]]; then
|
||||
log_info "Skipping hooks: ${SKIP}"
|
||||
fi
|
||||
|
||||
# Build pre-commit command
|
||||
PRE_COMMIT_CMD="pre-commit run"
|
||||
|
||||
# Handle files mode
|
||||
if [[ "${FILES_MODE}" == "staged" ]]; then
|
||||
# Run on staged files only (no flag needed, this is default for 'pre-commit run')
|
||||
log_info "Running on staged files only"
|
||||
else
|
||||
PRE_COMMIT_CMD="${PRE_COMMIT_CMD} --all-files"
|
||||
fi
|
||||
|
||||
# Add specific hook if provided
|
||||
if [[ -n "${HOOK_ID:-}" ]]; then
|
||||
PRE_COMMIT_CMD="${PRE_COMMIT_CMD} ${HOOK_ID}"
|
||||
fi
|
||||
|
||||
# Execute the validation
|
||||
log_info "Executing: ${PRE_COMMIT_CMD}"
|
||||
|
||||
if eval "${PRE_COMMIT_CMD}"; then
|
||||
log_success "All pre-commit hooks passed"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
log_error "One or more pre-commit hooks failed (exit code: ${exit_code})"
|
||||
log_info "Review the output above for details"
|
||||
log_info "Some hooks can auto-fix issues - review and commit changes if appropriate"
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
353
.github/skills/qa-precommit-all.SKILL.md
vendored
Normal file
353
.github/skills/qa-precommit-all.SKILL.md
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "qa-precommit-all"
|
||||
version: "1.0.0"
|
||||
description: "Run all pre-commit hooks for comprehensive code quality validation"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "qa"
|
||||
- "quality"
|
||||
- "pre-commit"
|
||||
- "linting"
|
||||
- "validation"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "python3"
|
||||
version: ">=3.8"
|
||||
optional: false
|
||||
- name: "pre-commit"
|
||||
version: ">=2.0"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "PRE_COMMIT_HOME"
|
||||
description: "Pre-commit cache directory"
|
||||
default: "~/.cache/pre-commit"
|
||||
required: false
|
||||
- name: "SKIP"
|
||||
description: "Comma-separated list of hook IDs to skip"
|
||||
default: ""
|
||||
required: false
|
||||
parameters:
|
||||
- name: "files"
|
||||
type: "string"
|
||||
description: "Specific files to check (default: all staged files)"
|
||||
default: "--all-files"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "validation_report"
|
||||
type: "stdout"
|
||||
description: "Results of all pre-commit hook executions"
|
||||
- name: "exit_code"
|
||||
type: "number"
|
||||
description: "0 if all hooks pass, non-zero if any fail"
|
||||
metadata:
|
||||
category: "qa"
|
||||
subcategory: "quality"
|
||||
execution_time: "medium"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# QA Pre-commit All
|
||||
|
||||
## Overview
|
||||
|
||||
Executes all configured pre-commit hooks to validate code quality, formatting, security, and best practices across the entire codebase. This skill runs checks for Python, Go, JavaScript/TypeScript, Markdown, YAML, and more.
|
||||
|
||||
This skill is designed for CI/CD pipelines and local quality validation before committing code.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Python 3.8 or higher installed and in PATH
|
||||
- Python virtual environment activated (`.venv`)
|
||||
- Pre-commit installed in virtual environment: `pip install pre-commit`
|
||||
- Pre-commit hooks installed: `pre-commit install`
|
||||
- All language-specific tools installed (Go, Node.js, etc.)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run all hooks on all files:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh qa-precommit-all
|
||||
```
|
||||
|
||||
### Staged Files Only
|
||||
|
||||
Run hooks on staged files only (faster):
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh qa-precommit-all staged
|
||||
```
|
||||
|
||||
### Specific Hook
|
||||
|
||||
Run only a specific hook by ID:
|
||||
|
||||
```bash
|
||||
SKIP="" .github/skills/scripts/skill-runner.sh qa-precommit-all trailing-whitespace
|
||||
```
|
||||
|
||||
### Skip Specific Hooks
|
||||
|
||||
Skip certain hooks during execution:
|
||||
|
||||
```bash
|
||||
SKIP=prettier,eslint .github/skills/scripts/skill-runner.sh qa-precommit-all
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| files | string | No | --all-files | File selection mode (--all-files or staged) |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| SKIP | No | "" | Comma-separated hook IDs to skip |
|
||||
| PRE_COMMIT_HOME | No | ~/.cache/pre-commit | Pre-commit cache directory |
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 (all hooks passed)
|
||||
- **Error Exit Codes**: Non-zero (one or more hooks failed)
|
||||
- **Output**: Detailed results from each hook
|
||||
|
||||
## Pre-commit Hooks Included
|
||||
|
||||
The following hooks are configured in `.pre-commit-config.yaml`:
|
||||
|
||||
### General Hooks
|
||||
- **trailing-whitespace**: Remove trailing whitespace
|
||||
- **end-of-file-fixer**: Ensure files end with newline
|
||||
- **check-yaml**: Validate YAML syntax
|
||||
- **check-json**: Validate JSON syntax
|
||||
- **check-merge-conflict**: Detect merge conflict markers
|
||||
- **check-added-large-files**: Prevent committing large files
|
||||
|
||||
### Python Hooks
|
||||
- **black**: Code formatting
|
||||
- **isort**: Import sorting
|
||||
- **flake8**: Linting
|
||||
- **mypy**: Type checking
|
||||
|
||||
### Go Hooks
|
||||
- **gofmt**: Code formatting
|
||||
- **go-vet**: Static analysis
|
||||
- **golangci-lint**: Comprehensive linting
|
||||
|
||||
### JavaScript/TypeScript Hooks
|
||||
- **prettier**: Code formatting
|
||||
- **eslint**: Linting and code quality
|
||||
|
||||
### Markdown Hooks
|
||||
- **markdownlint**: Markdown linting and formatting
|
||||
|
||||
### Security Hooks
|
||||
- **detect-private-key**: Prevent committing private keys
|
||||
- **detect-aws-credentials**: Prevent committing AWS credentials
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Full Quality Check
|
||||
|
||||
```bash
|
||||
# Run all hooks on all files
|
||||
source .venv/bin/activate
|
||||
.github/skills/scripts/skill-runner.sh qa-precommit-all
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
Trim Trailing Whitespace.....................................Passed
|
||||
Fix End of Files.............................................Passed
|
||||
Check Yaml...................................................Passed
|
||||
Check JSON...................................................Passed
|
||||
Check for merge conflicts....................................Passed
|
||||
Check for added large files..................................Passed
|
||||
black........................................................Passed
|
||||
isort........................................................Passed
|
||||
prettier.....................................................Passed
|
||||
eslint.......................................................Passed
|
||||
markdownlint.................................................Passed
|
||||
```
|
||||
|
||||
### Example 2: Quick Staged Files Check
|
||||
|
||||
```bash
|
||||
# Run only on staged files (faster for pre-commit)
|
||||
.github/skills/scripts/skill-runner.sh qa-precommit-all staged
|
||||
```
|
||||
|
||||
### Example 3: Skip Slow Hooks
|
||||
|
||||
```bash
|
||||
# Skip time-consuming hooks for quick validation
|
||||
SKIP=golangci-lint,mypy .github/skills/scripts/skill-runner.sh qa-precommit-all
|
||||
```
|
||||
|
||||
### Example 4: CI/CD Pipeline Integration
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.11'
|
||||
|
||||
- name: Install pre-commit
|
||||
run: pip install pre-commit
|
||||
|
||||
- name: Run QA Pre-commit Checks
|
||||
run: .github/skills/scripts/skill-runner.sh qa-precommit-all
|
||||
```
|
||||
|
||||
### Example 5: Auto-fix Mode
|
||||
|
||||
```bash
|
||||
# Some hooks can auto-fix issues
|
||||
# Run twice: first to fix, second to validate
|
||||
.github/skills/scripts/skill-runner.sh qa-precommit-all || \
|
||||
.github/skills/scripts/skill-runner.sh qa-precommit-all
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Virtual environment not activated**:
|
||||
```bash
|
||||
Error: pre-commit not found
|
||||
Solution: source .venv/bin/activate
|
||||
```
|
||||
|
||||
**Pre-commit not installed**:
|
||||
```bash
|
||||
Error: pre-commit command not available
|
||||
Solution: pip install pre-commit
|
||||
```
|
||||
|
||||
**Hooks not installed**:
|
||||
```bash
|
||||
Error: Run 'pre-commit install'
|
||||
Solution: pre-commit install
|
||||
```
|
||||
|
||||
**Hook execution failed**:
|
||||
```bash
|
||||
Hook X failed
|
||||
Solution: Review error output and fix reported issues
|
||||
```
|
||||
|
||||
**Language tool missing**:
|
||||
```bash
|
||||
Error: golangci-lint not found
|
||||
Solution: Install required language tools
|
||||
```
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- **0**: All hooks passed
|
||||
- **1**: One or more hooks failed
|
||||
- **Other**: Hook execution error
|
||||
|
||||
## Hook Fixing Strategies
|
||||
|
||||
### Auto-fixable Issues
|
||||
These hooks automatically fix issues:
|
||||
- `trailing-whitespace`
|
||||
- `end-of-file-fixer`
|
||||
- `black`
|
||||
- `isort`
|
||||
- `prettier`
|
||||
- `gofmt`
|
||||
|
||||
**Workflow**: Run pre-commit, review changes, commit fixed files
|
||||
|
||||
### Manual Fixes Required
|
||||
These hooks only report issues:
|
||||
- `check-yaml`
|
||||
- `check-json`
|
||||
- `flake8`
|
||||
- `eslint`
|
||||
- `markdownlint`
|
||||
- `go-vet`
|
||||
- `golangci-lint`
|
||||
|
||||
**Workflow**: Review errors, manually fix code, re-run pre-commit
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [test-backend-coverage](./test-backend-coverage.SKILL.md) - Backend test coverage
|
||||
- [test-frontend-coverage](./test-frontend-coverage.SKILL.md) - Frontend test coverage
|
||||
- [security-scan-trivy](./security-scan-trivy.SKILL.md) - Security scanning
|
||||
|
||||
## Notes
|
||||
|
||||
- Pre-commit hooks cache their environments for faster execution
|
||||
- First run may be slow while environments are set up
|
||||
- Subsequent runs are much faster (seconds vs minutes)
|
||||
- Hooks run in parallel where possible
|
||||
- Failed hooks stop execution (fail-fast behavior)
|
||||
- Use `SKIP` to bypass specific hooks temporarily
|
||||
- Recommended to run before every commit
|
||||
- Can be integrated into Git pre-commit hook for automatic checks
|
||||
- Cache location: `~/.cache/pre-commit` (configurable)
|
||||
|
||||
## Performance Tips
|
||||
|
||||
- **Initial Setup**: First run takes longer (installing hook environments)
|
||||
- **Incremental**: Run on staged files only for faster feedback
|
||||
- **Parallel**: Pre-commit runs compatible hooks in parallel
|
||||
- **Cache**: Hook environments are cached and reused
|
||||
- **Skip**: Use `SKIP` to bypass slow hooks during development
|
||||
|
||||
## Integration with Git
|
||||
|
||||
To automatically run on every commit:
|
||||
|
||||
```bash
|
||||
# Install Git pre-commit hook
|
||||
pre-commit install
|
||||
|
||||
# Now pre-commit runs automatically on git commit
|
||||
git commit -m "Your commit message"
|
||||
```
|
||||
|
||||
To bypass pre-commit hook temporarily:
|
||||
|
||||
```bash
|
||||
git commit --no-verify -m "Emergency commit"
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
Pre-commit configuration is in `.pre-commit-config.yaml`. To update hooks:
|
||||
|
||||
```bash
|
||||
# Update to latest versions
|
||||
pre-commit autoupdate
|
||||
|
||||
# Clean cache and re-install
|
||||
pre-commit clean
|
||||
pre-commit install --install-hooks
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: `pre-commit run --all-files`
|
||||
202
.github/skills/scripts/_environment_helpers.sh
vendored
Executable file
202
.github/skills/scripts/_environment_helpers.sh
vendored
Executable file
@@ -0,0 +1,202 @@
|
||||
#!/usr/bin/env bash
|
||||
# Agent Skills - Environment Helpers
|
||||
#
|
||||
# Provides environment validation and setup utilities.
|
||||
|
||||
# validate_go_environment: Check Go installation and version
|
||||
validate_go_environment() {
|
||||
local min_version="${1:-1.23}"
|
||||
|
||||
if ! command -v go >/dev/null 2>&1; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Go is not installed or not in PATH"
|
||||
else
|
||||
echo "[ERROR] Go is not installed or not in PATH" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
local go_version
|
||||
go_version=$(go version | grep -oP 'go\K[0-9]+\.[0-9]+' || echo "0.0")
|
||||
|
||||
if declare -f log_debug >/dev/null 2>&1; then
|
||||
log_debug "Go version: ${go_version} (required: >=${min_version})"
|
||||
fi
|
||||
|
||||
# Simple version comparison (assumes semantic versioning)
|
||||
if [[ "$(printf '%s\n' "${min_version}" "${go_version}" | sort -V | head -n1)" != "${min_version}" ]]; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Go version ${go_version} is below minimum required version ${min_version}"
|
||||
else
|
||||
echo "[ERROR] Go version ${go_version} is below minimum required version ${min_version}" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# validate_python_environment: Check Python installation and version
|
||||
validate_python_environment() {
|
||||
local min_version="${1:-3.8}"
|
||||
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Python 3 is not installed or not in PATH"
|
||||
else
|
||||
echo "[ERROR] Python 3 is not installed or not in PATH" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
local python_version
|
||||
python_version=$(python3 --version 2>&1 | grep -oP 'Python \K[0-9]+\.[0-9]+' || echo "0.0")
|
||||
|
||||
if declare -f log_debug >/dev/null 2>&1; then
|
||||
log_debug "Python version: ${python_version} (required: >=${min_version})"
|
||||
fi
|
||||
|
||||
# Simple version comparison
|
||||
if [[ "$(printf '%s\n' "${min_version}" "${python_version}" | sort -V | head -n1)" != "${min_version}" ]]; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Python version ${python_version} is below minimum required version ${min_version}"
|
||||
else
|
||||
echo "[ERROR] Python version ${python_version} is below minimum required version ${min_version}" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# validate_node_environment: Check Node.js installation and version
|
||||
validate_node_environment() {
|
||||
local min_version="${1:-18.0}"
|
||||
|
||||
if ! command -v node >/dev/null 2>&1; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Node.js is not installed or not in PATH"
|
||||
else
|
||||
echo "[ERROR] Node.js is not installed or not in PATH" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
local node_version
|
||||
node_version=$(node --version | grep -oP 'v\K[0-9]+\.[0-9]+' || echo "0.0")
|
||||
|
||||
if declare -f log_debug >/dev/null 2>&1; then
|
||||
log_debug "Node.js version: ${node_version} (required: >=${min_version})"
|
||||
fi
|
||||
|
||||
# Simple version comparison
|
||||
if [[ "$(printf '%s\n' "${min_version}" "${node_version}" | sort -V | head -n1)" != "${min_version}" ]]; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Node.js version ${node_version} is below minimum required version ${min_version}"
|
||||
else
|
||||
echo "[ERROR] Node.js version ${node_version} is below minimum required version ${min_version}" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# validate_docker_environment: Check Docker installation and daemon
|
||||
validate_docker_environment() {
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Docker is not installed or not in PATH"
|
||||
else
|
||||
echo "[ERROR] Docker is not installed or not in PATH" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if Docker daemon is running
|
||||
if ! docker info >/dev/null 2>&1; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Docker daemon is not running"
|
||||
else
|
||||
echo "[ERROR] Docker daemon is not running" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if declare -f log_debug >/dev/null 2>&1; then
|
||||
local docker_version
|
||||
docker_version=$(docker --version | grep -oP 'Docker version \K[0-9]+\.[0-9]+\.[0-9]+' || echo "unknown")
|
||||
log_debug "Docker version: ${docker_version}"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# set_default_env: Set environment variable with default value if not set
|
||||
set_default_env() {
|
||||
local var_name="$1"
|
||||
local default_value="$2"
|
||||
|
||||
if [[ -z "${!var_name:-}" ]]; then
|
||||
export "${var_name}=${default_value}"
|
||||
|
||||
if declare -f log_debug >/dev/null 2>&1; then
|
||||
log_debug "Set ${var_name}=${default_value} (default)"
|
||||
fi
|
||||
else
|
||||
if declare -f log_debug >/dev/null 2>&1; then
|
||||
log_debug "Using ${var_name}=${!var_name} (from environment)"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# validate_project_structure: Check we're in the correct project directory
|
||||
validate_project_structure() {
|
||||
local required_files=("$@")
|
||||
|
||||
for file in "${required_files[@]}"; do
|
||||
if [[ ! -e "${file}" ]]; then
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Required file/directory not found: ${file}"
|
||||
log_error "Are you running this from the project root?"
|
||||
else
|
||||
echo "[ERROR] Required file/directory not found: ${file}" >&2
|
||||
echo "[ERROR] Are you running this from the project root?" >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# get_project_root: Find project root by looking for marker files
|
||||
get_project_root() {
|
||||
local marker_file="${1:-.git}"
|
||||
local current_dir
|
||||
current_dir="$(pwd)"
|
||||
|
||||
while [[ "${current_dir}" != "/" ]]; do
|
||||
if [[ -e "${current_dir}/${marker_file}" ]]; then
|
||||
echo "${current_dir}"
|
||||
return 0
|
||||
fi
|
||||
current_dir="$(dirname "${current_dir}")"
|
||||
done
|
||||
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Could not find project root (looking for ${marker_file})"
|
||||
else
|
||||
echo "[ERROR] Could not find project root (looking for ${marker_file})" >&2
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f validate_go_environment
|
||||
export -f validate_python_environment
|
||||
export -f validate_node_environment
|
||||
export -f validate_docker_environment
|
||||
export -f set_default_env
|
||||
export -f validate_project_structure
|
||||
export -f get_project_root
|
||||
134
.github/skills/scripts/_error_handling_helpers.sh
vendored
Executable file
134
.github/skills/scripts/_error_handling_helpers.sh
vendored
Executable file
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env bash
|
||||
# Agent Skills - Error Handling Helpers
|
||||
#
|
||||
# Provides error handling utilities for robust skill execution.
|
||||
|
||||
# error_exit: Print error message and exit with code
|
||||
error_exit() {
|
||||
local message="$1"
|
||||
local exit_code="${2:-1}"
|
||||
|
||||
# Source logging helpers if not already loaded
|
||||
if ! declare -f log_error >/dev/null 2>&1; then
|
||||
echo "[ERROR] ${message}" >&2
|
||||
else
|
||||
log_error "${message}"
|
||||
fi
|
||||
|
||||
exit "${exit_code}"
|
||||
}
|
||||
|
||||
# check_command_exists: Verify a command is available
|
||||
check_command_exists() {
|
||||
local cmd="$1"
|
||||
local error_msg="${2:-Command not found: ${cmd}}"
|
||||
|
||||
if ! command -v "${cmd}" >/dev/null 2>&1; then
|
||||
error_exit "${error_msg}" 127
|
||||
fi
|
||||
}
|
||||
|
||||
# check_file_exists: Verify a file exists
|
||||
check_file_exists() {
|
||||
local file="$1"
|
||||
local error_msg="${2:-File not found: ${file}}"
|
||||
|
||||
if [[ ! -f "${file}" ]]; then
|
||||
error_exit "${error_msg}" 1
|
||||
fi
|
||||
}
|
||||
|
||||
# check_dir_exists: Verify a directory exists
|
||||
check_dir_exists() {
|
||||
local dir="$1"
|
||||
local error_msg="${2:-Directory not found: ${dir}}"
|
||||
|
||||
if [[ ! -d "${dir}" ]]; then
|
||||
error_exit "${error_msg}" 1
|
||||
fi
|
||||
}
|
||||
|
||||
# check_exit_code: Verify previous command succeeded
|
||||
check_exit_code() {
|
||||
local exit_code=$?
|
||||
local error_msg="${1:-Command failed with exit code ${exit_code}}"
|
||||
|
||||
if [[ ${exit_code} -ne 0 ]]; then
|
||||
error_exit "${error_msg}" "${exit_code}"
|
||||
fi
|
||||
}
|
||||
|
||||
# run_with_retry: Run a command with retry logic
|
||||
run_with_retry() {
|
||||
local max_attempts="${1}"
|
||||
local delay="${2}"
|
||||
shift 2
|
||||
local cmd=("$@")
|
||||
|
||||
local attempt=1
|
||||
while [[ ${attempt} -le ${max_attempts} ]]; do
|
||||
if "${cmd[@]}"; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ ${attempt} -lt ${max_attempts} ]]; then
|
||||
if declare -f log_warning >/dev/null 2>&1; then
|
||||
log_warning "Command failed (attempt ${attempt}/${max_attempts}). Retrying in ${delay}s..."
|
||||
else
|
||||
echo "[WARNING] Command failed (attempt ${attempt}/${max_attempts}). Retrying in ${delay}s..." >&2
|
||||
fi
|
||||
sleep "${delay}"
|
||||
fi
|
||||
|
||||
((attempt++))
|
||||
done
|
||||
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Command failed after ${max_attempts} attempts: ${cmd[*]}"
|
||||
else
|
||||
echo "[ERROR] Command failed after ${max_attempts} attempts: ${cmd[*]}" >&2
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# trap_error: Set up error trapping for the current script
|
||||
trap_error() {
|
||||
local script_name="${1:-${BASH_SOURCE[1]}}"
|
||||
|
||||
trap 'error_handler ${LINENO} ${BASH_LINENO} "${BASH_COMMAND}" "${script_name}"' ERR
|
||||
}
|
||||
|
||||
# error_handler: Internal error handler for trap
|
||||
error_handler() {
|
||||
local line_no="$1"
|
||||
local bash_line_no="$2"
|
||||
local command="$3"
|
||||
local script="$4"
|
||||
|
||||
if declare -f log_error >/dev/null 2>&1; then
|
||||
log_error "Script failed at line ${line_no} in ${script}"
|
||||
log_error "Command: ${command}"
|
||||
else
|
||||
echo "[ERROR] Script failed at line ${line_no} in ${script}" >&2
|
||||
echo "[ERROR] Command: ${command}" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# cleanup_on_exit: Register a cleanup function to run on exit
|
||||
cleanup_on_exit() {
|
||||
local cleanup_func="$1"
|
||||
|
||||
# Register cleanup function
|
||||
trap "${cleanup_func}" EXIT
|
||||
}
|
||||
|
||||
# Export functions
|
||||
export -f error_exit
|
||||
export -f check_command_exists
|
||||
export -f check_file_exists
|
||||
export -f check_dir_exists
|
||||
export -f check_exit_code
|
||||
export -f run_with_retry
|
||||
export -f trap_error
|
||||
export -f error_handler
|
||||
export -f cleanup_on_exit
|
||||
109
.github/skills/scripts/_logging_helpers.sh
vendored
Executable file
109
.github/skills/scripts/_logging_helpers.sh
vendored
Executable file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/env bash
|
||||
# Agent Skills - Logging Helpers
|
||||
#
|
||||
# Provides colored logging functions for consistent output across all skills.
|
||||
|
||||
# Color codes
|
||||
readonly COLOR_RESET="\033[0m"
|
||||
readonly COLOR_RED="\033[0;31m"
|
||||
readonly COLOR_GREEN="\033[0;32m"
|
||||
readonly COLOR_YELLOW="\033[0;33m"
|
||||
readonly COLOR_BLUE="\033[0;34m"
|
||||
readonly COLOR_MAGENTA="\033[0;35m"
|
||||
readonly COLOR_CYAN="\033[0;36m"
|
||||
readonly COLOR_GRAY="\033[0;90m"
|
||||
|
||||
# Check if output is a terminal (for color support)
|
||||
if [[ -t 1 ]]; then
|
||||
COLORS_ENABLED=true
|
||||
else
|
||||
COLORS_ENABLED=false
|
||||
fi
|
||||
|
||||
# Disable colors if NO_COLOR environment variable is set
|
||||
if [[ -n "${NO_COLOR:-}" ]]; then
|
||||
COLORS_ENABLED=false
|
||||
fi
|
||||
|
||||
# log_info: Print informational message
|
||||
log_info() {
|
||||
local message="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_BLUE}[INFO]${COLOR_RESET} ${message}"
|
||||
else
|
||||
echo "[INFO] ${message}"
|
||||
fi
|
||||
}
|
||||
|
||||
# log_success: Print success message
|
||||
log_success() {
|
||||
local message="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_GREEN}[SUCCESS]${COLOR_RESET} ${message}"
|
||||
else
|
||||
echo "[SUCCESS] ${message}"
|
||||
fi
|
||||
}
|
||||
|
||||
# log_warning: Print warning message
|
||||
log_warning() {
|
||||
local message="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_YELLOW}[WARNING]${COLOR_RESET} ${message}" >&2
|
||||
else
|
||||
echo "[WARNING] ${message}" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# log_error: Print error message
|
||||
log_error() {
|
||||
local message="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_RED}[ERROR]${COLOR_RESET} ${message}" >&2
|
||||
else
|
||||
echo "[ERROR] ${message}" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# log_debug: Print debug message (only if DEBUG=1)
|
||||
log_debug() {
|
||||
if [[ "${DEBUG:-0}" == "1" ]]; then
|
||||
local message="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_GRAY}[DEBUG]${COLOR_RESET} ${message}"
|
||||
else
|
||||
echo "[DEBUG] ${message}"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# log_step: Print step header
|
||||
log_step() {
|
||||
local step_name="$1"
|
||||
shift
|
||||
local message="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_CYAN}[${step_name}]${COLOR_RESET} ${message}"
|
||||
else
|
||||
echo "[${step_name}] ${message}"
|
||||
fi
|
||||
}
|
||||
|
||||
# log_command: Log a command before executing (for transparency)
|
||||
log_command() {
|
||||
local command="$*"
|
||||
if [[ "${COLORS_ENABLED}" == "true" ]]; then
|
||||
echo -e "${COLOR_MAGENTA}[$]${COLOR_RESET} ${command}"
|
||||
else
|
||||
echo "[\$] ${command}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Export functions so they can be used by sourcing scripts
|
||||
export -f log_info
|
||||
export -f log_success
|
||||
export -f log_warning
|
||||
export -f log_error
|
||||
export -f log_debug
|
||||
export -f log_step
|
||||
export -f log_command
|
||||
96
.github/skills/scripts/skill-runner.sh
vendored
Executable file
96
.github/skills/scripts/skill-runner.sh
vendored
Executable file
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
# Agent Skills Universal Skill Runner
|
||||
#
|
||||
# This script locates and executes Agent Skills by name, providing a unified
|
||||
# interface for running skills from tasks.json, CI/CD workflows, and the CLI.
|
||||
#
|
||||
# Usage:
|
||||
# skill-runner.sh <skill-name> [args...]
|
||||
#
|
||||
# Exit Codes:
|
||||
# 0 - Skill executed successfully
|
||||
# 1 - Skill not found or invalid
|
||||
# 2 - Skill execution failed
|
||||
# 126 - Skill script not executable
|
||||
# 127 - Skill script not found
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# shellcheck source=_logging_helpers.sh
|
||||
source "${SCRIPT_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=_error_handling_helpers.sh
|
||||
source "${SCRIPT_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=_environment_helpers.sh
|
||||
source "${SCRIPT_DIR}/_environment_helpers.sh"
|
||||
|
||||
# Configuration
|
||||
SKILLS_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SKILLS_DIR}/../.." && pwd)"
|
||||
|
||||
# Validate arguments
|
||||
if [[ $# -eq 0 ]]; then
|
||||
log_error "Usage: skill-runner.sh <skill-name> [args...]"
|
||||
log_error "Example: skill-runner.sh test-backend-coverage"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
SKILL_NAME="$1"
|
||||
shift # Remove skill name from arguments
|
||||
|
||||
# Validate skill name format
|
||||
if [[ ! "${SKILL_NAME}" =~ ^[a-z][a-z0-9-]*$ ]]; then
|
||||
log_error "Invalid skill name: ${SKILL_NAME}"
|
||||
log_error "Skill names must be kebab-case (lowercase, hyphens, start with letter)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Verify SKILL.md exists
|
||||
SKILL_FILE="${SKILLS_DIR}/${SKILL_NAME}.SKILL.md"
|
||||
if [[ ! -f "${SKILL_FILE}" ]]; then
|
||||
log_error "Skill not found: ${SKILL_NAME}"
|
||||
log_error "Expected file: ${SKILL_FILE}"
|
||||
log_info "Available skills:"
|
||||
for skill_file in "${SKILLS_DIR}"/*.SKILL.md; do
|
||||
if [[ -f "${skill_file}" ]]; then
|
||||
basename "${skill_file}" .SKILL.md
|
||||
fi
|
||||
done | sort | sed 's/^/ - /'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Locate skill execution script (flat structure: skill-name-scripts/run.sh)
|
||||
SKILL_SCRIPT="${SKILLS_DIR}/${SKILL_NAME}-scripts/run.sh"
|
||||
|
||||
if [[ ! -f "${SKILL_SCRIPT}" ]]; then
|
||||
log_error "Skill execution script not found: ${SKILL_SCRIPT}"
|
||||
log_error "Expected: ${SKILL_NAME}-scripts/run.sh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -x "${SKILL_SCRIPT}" ]]; then
|
||||
log_error "Skill execution script is not executable: ${SKILL_SCRIPT}"
|
||||
log_error "Fix with: chmod +x ${SKILL_SCRIPT}"
|
||||
exit 126
|
||||
fi
|
||||
|
||||
# Log skill execution
|
||||
log_info "Executing skill: ${SKILL_NAME}"
|
||||
log_debug "Skill file: ${SKILL_FILE}"
|
||||
log_debug "Skill script: ${SKILL_SCRIPT}"
|
||||
log_debug "Working directory: ${PROJECT_ROOT}"
|
||||
log_debug "Arguments: $*"
|
||||
|
||||
# Change to project root for execution
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
# Execute skill with all remaining arguments
|
||||
# shellcheck disable=SC2294
|
||||
if ! "${SKILL_SCRIPT}" "$@"; then
|
||||
log_error "Skill execution failed: ${SKILL_NAME}"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
log_success "Skill completed successfully: ${SKILL_NAME}"
|
||||
exit 0
|
||||
422
.github/skills/scripts/validate-skills.py
vendored
Executable file
422
.github/skills/scripts/validate-skills.py
vendored
Executable file
@@ -0,0 +1,422 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Agent Skills Frontmatter Validator
|
||||
|
||||
Validates YAML frontmatter in .SKILL.md files against the agentskills.io
|
||||
specification. Ensures required fields are present, formats are correct,
|
||||
and custom metadata follows project conventions.
|
||||
|
||||
Usage:
|
||||
python3 validate-skills.py [path/to/.github/skills/]
|
||||
python3 validate-skills.py --single path/to/skill.SKILL.md
|
||||
|
||||
Exit Codes:
|
||||
0 - All validations passed
|
||||
1 - Validation errors found
|
||||
2 - Script error (missing dependencies, invalid arguments)
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
import argparse
|
||||
from pathlib import Path
|
||||
from typing import List, Dict, Tuple, Any, Optional
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
print("Error: PyYAML is required. Install with: pip install pyyaml", file=sys.stderr)
|
||||
sys.exit(2)
|
||||
|
||||
|
||||
# Validation rules
|
||||
REQUIRED_FIELDS = ["name", "version", "description", "author", "license", "tags"]
|
||||
VALID_CATEGORIES = ["test", "integration-test", "security", "qa", "build", "utility", "docker"]
|
||||
VALID_EXECUTION_TIMES = ["short", "medium", "long"]
|
||||
VALID_RISK_LEVELS = ["low", "medium", "high"]
|
||||
VALID_OS_VALUES = ["linux", "darwin", "windows"]
|
||||
VALID_SHELL_VALUES = ["bash", "sh", "zsh", "powershell", "cmd"]
|
||||
|
||||
VERSION_REGEX = re.compile(r'^\d+\.\d+\.\d+$')
|
||||
NAME_REGEX = re.compile(r'^[a-z][a-z0-9-]*$')
|
||||
|
||||
|
||||
class ValidationError:
|
||||
"""Represents a validation error with context."""
|
||||
|
||||
def __init__(self, skill_file: str, field: str, message: str, severity: str = "error"):
|
||||
self.skill_file = skill_file
|
||||
self.field = field
|
||||
self.message = message
|
||||
self.severity = severity
|
||||
|
||||
def __str__(self) -> str:
|
||||
return f"[{self.severity.upper()}] {self.skill_file} :: {self.field}: {self.message}"
|
||||
|
||||
|
||||
class SkillValidator:
|
||||
"""Validates Agent Skills frontmatter."""
|
||||
|
||||
def __init__(self, strict: bool = False):
|
||||
self.strict = strict
|
||||
self.errors: List[ValidationError] = []
|
||||
self.warnings: List[ValidationError] = []
|
||||
|
||||
def validate_file(self, skill_path: Path) -> Tuple[bool, List[ValidationError]]:
|
||||
"""Validate a single SKILL.md file."""
|
||||
try:
|
||||
with open(skill_path, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
except Exception as e:
|
||||
return False, [ValidationError(str(skill_path), "file", f"Cannot read file: {e}")]
|
||||
|
||||
# Extract frontmatter
|
||||
frontmatter = self._extract_frontmatter(content)
|
||||
if not frontmatter:
|
||||
return False, [ValidationError(str(skill_path), "frontmatter", "No valid YAML frontmatter found")]
|
||||
|
||||
# Parse YAML
|
||||
try:
|
||||
data = yaml.safe_load(frontmatter)
|
||||
except yaml.YAMLError as e:
|
||||
return False, [ValidationError(str(skill_path), "yaml", f"Invalid YAML: {e}")]
|
||||
|
||||
if not isinstance(data, dict):
|
||||
return False, [ValidationError(str(skill_path), "yaml", "Frontmatter must be a YAML object")]
|
||||
|
||||
# Run validation checks
|
||||
file_errors: List[ValidationError] = []
|
||||
file_errors.extend(self._validate_required_fields(skill_path, data))
|
||||
file_errors.extend(self._validate_name(skill_path, data))
|
||||
file_errors.extend(self._validate_version(skill_path, data))
|
||||
file_errors.extend(self._validate_description(skill_path, data))
|
||||
file_errors.extend(self._validate_tags(skill_path, data))
|
||||
file_errors.extend(self._validate_compatibility(skill_path, data))
|
||||
file_errors.extend(self._validate_metadata(skill_path, data))
|
||||
|
||||
# Separate errors and warnings
|
||||
errors = [e for e in file_errors if e.severity == "error"]
|
||||
warnings = [e for e in file_errors if e.severity == "warning"]
|
||||
|
||||
self.errors.extend(errors)
|
||||
self.warnings.extend(warnings)
|
||||
|
||||
return len(errors) == 0, file_errors
|
||||
|
||||
def _extract_frontmatter(self, content: str) -> Optional[str]:
|
||||
"""Extract YAML frontmatter from markdown content."""
|
||||
if not content.startswith('---\n'):
|
||||
return None
|
||||
|
||||
end_marker = content.find('\n---\n', 4)
|
||||
if end_marker == -1:
|
||||
return None
|
||||
|
||||
return content[4:end_marker]
|
||||
|
||||
def _validate_required_fields(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Check that all required fields are present."""
|
||||
errors = []
|
||||
for field in REQUIRED_FIELDS:
|
||||
if field not in data:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), field, f"Required field missing"
|
||||
))
|
||||
elif not data[field]:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), field, f"Required field is empty"
|
||||
))
|
||||
return errors
|
||||
|
||||
def _validate_name(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Validate name field format."""
|
||||
errors = []
|
||||
if "name" in data:
|
||||
name = data["name"]
|
||||
if not isinstance(name, str):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "name", "Must be a string"
|
||||
))
|
||||
elif not NAME_REGEX.match(name):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "name",
|
||||
"Must be kebab-case (lowercase, hyphens only, start with letter)"
|
||||
))
|
||||
return errors
|
||||
|
||||
def _validate_version(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Validate version field format."""
|
||||
errors = []
|
||||
if "version" in data:
|
||||
version = data["version"]
|
||||
if not isinstance(version, str):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "version", "Must be a string"
|
||||
))
|
||||
elif not VERSION_REGEX.match(version):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "version",
|
||||
"Must follow semantic versioning (x.y.z)"
|
||||
))
|
||||
return errors
|
||||
|
||||
def _validate_description(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Validate description field."""
|
||||
errors = []
|
||||
if "description" in data:
|
||||
desc = data["description"]
|
||||
if not isinstance(desc, str):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "description", "Must be a string"
|
||||
))
|
||||
elif len(desc) > 120:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "description",
|
||||
f"Must be 120 characters or less (current: {len(desc)})"
|
||||
))
|
||||
elif '\n' in desc:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "description", "Must be a single line"
|
||||
))
|
||||
return errors
|
||||
|
||||
def _validate_tags(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Validate tags field."""
|
||||
errors = []
|
||||
if "tags" in data:
|
||||
tags = data["tags"]
|
||||
if not isinstance(tags, list):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "tags", "Must be a list"
|
||||
))
|
||||
elif len(tags) < 2:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "tags", "Must have at least 2 tags"
|
||||
))
|
||||
elif len(tags) > 5:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "tags",
|
||||
f"Must have at most 5 tags (current: {len(tags)})",
|
||||
severity="warning"
|
||||
))
|
||||
else:
|
||||
for tag in tags:
|
||||
if not isinstance(tag, str):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "tags", "All tags must be strings"
|
||||
))
|
||||
elif tag != tag.lower():
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "tags",
|
||||
f"Tag '{tag}' should be lowercase",
|
||||
severity="warning"
|
||||
))
|
||||
return errors
|
||||
|
||||
def _validate_compatibility(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Validate compatibility section."""
|
||||
errors = []
|
||||
if "compatibility" in data:
|
||||
compat = data["compatibility"]
|
||||
if not isinstance(compat, dict):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "compatibility", "Must be an object"
|
||||
))
|
||||
else:
|
||||
# Validate OS
|
||||
if "os" in compat:
|
||||
os_list = compat["os"]
|
||||
if not isinstance(os_list, list):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "compatibility.os", "Must be a list"
|
||||
))
|
||||
else:
|
||||
for os_val in os_list:
|
||||
if os_val not in VALID_OS_VALUES:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "compatibility.os",
|
||||
f"Invalid OS '{os_val}'. Valid: {VALID_OS_VALUES}",
|
||||
severity="warning"
|
||||
))
|
||||
|
||||
# Validate shells
|
||||
if "shells" in compat:
|
||||
shells = compat["shells"]
|
||||
if not isinstance(shells, list):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "compatibility.shells", "Must be a list"
|
||||
))
|
||||
else:
|
||||
for shell in shells:
|
||||
if shell not in VALID_SHELL_VALUES:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "compatibility.shells",
|
||||
f"Invalid shell '{shell}'. Valid: {VALID_SHELL_VALUES}",
|
||||
severity="warning"
|
||||
))
|
||||
return errors
|
||||
|
||||
def _validate_metadata(self, skill_path: Path, data: Dict) -> List[ValidationError]:
|
||||
"""Validate custom metadata section."""
|
||||
errors = []
|
||||
if "metadata" not in data:
|
||||
return errors # Metadata is optional
|
||||
|
||||
metadata = data["metadata"]
|
||||
if not isinstance(metadata, dict):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "metadata", "Must be an object"
|
||||
))
|
||||
return errors
|
||||
|
||||
# Validate category
|
||||
if "category" in metadata:
|
||||
category = metadata["category"]
|
||||
if category not in VALID_CATEGORIES:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "metadata.category",
|
||||
f"Invalid category '{category}'. Valid: {VALID_CATEGORIES}",
|
||||
severity="warning"
|
||||
))
|
||||
|
||||
# Validate execution_time
|
||||
if "execution_time" in metadata:
|
||||
exec_time = metadata["execution_time"]
|
||||
if exec_time not in VALID_EXECUTION_TIMES:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "metadata.execution_time",
|
||||
f"Invalid execution_time '{exec_time}'. Valid: {VALID_EXECUTION_TIMES}",
|
||||
severity="warning"
|
||||
))
|
||||
|
||||
# Validate risk_level
|
||||
if "risk_level" in metadata:
|
||||
risk = metadata["risk_level"]
|
||||
if risk not in VALID_RISK_LEVELS:
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), "metadata.risk_level",
|
||||
f"Invalid risk_level '{risk}'. Valid: {VALID_RISK_LEVELS}",
|
||||
severity="warning"
|
||||
))
|
||||
|
||||
# Validate boolean fields
|
||||
for bool_field in ["ci_cd_safe", "requires_network", "idempotent"]:
|
||||
if bool_field in metadata:
|
||||
if not isinstance(metadata[bool_field], bool):
|
||||
errors.append(ValidationError(
|
||||
str(skill_path), f"metadata.{bool_field}",
|
||||
"Must be a boolean (true/false)",
|
||||
severity="warning"
|
||||
))
|
||||
|
||||
return errors
|
||||
|
||||
def validate_directory(self, skills_dir: Path) -> bool:
|
||||
"""Validate all SKILL.md files in a directory."""
|
||||
if not skills_dir.exists():
|
||||
print(f"Error: Directory not found: {skills_dir}", file=sys.stderr)
|
||||
return False
|
||||
|
||||
skill_files = list(skills_dir.glob("*.SKILL.md"))
|
||||
if not skill_files:
|
||||
print(f"Warning: No .SKILL.md files found in {skills_dir}", file=sys.stderr)
|
||||
return True # Not an error, just nothing to validate
|
||||
|
||||
print(f"Validating {len(skill_files)} skill(s)...\n")
|
||||
|
||||
success_count = 0
|
||||
for skill_file in sorted(skill_files):
|
||||
is_valid, _ = self.validate_file(skill_file)
|
||||
if is_valid:
|
||||
success_count += 1
|
||||
print(f"✓ {skill_file.name}")
|
||||
else:
|
||||
print(f"✗ {skill_file.name}")
|
||||
|
||||
# Print summary
|
||||
print(f"\n{'='*70}")
|
||||
print(f"Validation Summary:")
|
||||
print(f" Total skills: {len(skill_files)}")
|
||||
print(f" Passed: {success_count}")
|
||||
print(f" Failed: {len(skill_files) - success_count}")
|
||||
print(f" Errors: {len(self.errors)}")
|
||||
print(f" Warnings: {len(self.warnings)}")
|
||||
print(f"{'='*70}\n")
|
||||
|
||||
# Print errors
|
||||
if self.errors:
|
||||
print("ERRORS:")
|
||||
for error in self.errors:
|
||||
print(f" {error}")
|
||||
print()
|
||||
|
||||
# Print warnings
|
||||
if self.warnings:
|
||||
print("WARNINGS:")
|
||||
for warning in self.warnings:
|
||||
print(f" {warning}")
|
||||
print()
|
||||
|
||||
return len(self.errors) == 0
|
||||
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Validate Agent Skills frontmatter",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog=__doc__
|
||||
)
|
||||
parser.add_argument(
|
||||
"path",
|
||||
nargs="?",
|
||||
default=".github/skills",
|
||||
help="Path to .github/skills directory or single .SKILL.md file (default: .github/skills)"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--strict",
|
||||
action="store_true",
|
||||
help="Treat warnings as errors"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--single",
|
||||
action="store_true",
|
||||
help="Validate a single .SKILL.md file instead of a directory"
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
validator = SkillValidator(strict=args.strict)
|
||||
path = Path(args.path)
|
||||
|
||||
if args.single:
|
||||
if not path.exists():
|
||||
print(f"Error: File not found: {path}", file=sys.stderr)
|
||||
return 2
|
||||
|
||||
is_valid, errors = validator.validate_file(path)
|
||||
|
||||
if is_valid:
|
||||
print(f"✓ {path.name} is valid")
|
||||
if errors: # Warnings only
|
||||
print("\nWARNINGS:")
|
||||
for error in errors:
|
||||
print(f" {error}")
|
||||
else:
|
||||
print(f"✗ {path.name} has errors")
|
||||
for error in errors:
|
||||
print(f" {error}")
|
||||
|
||||
return 0 if is_valid else 1
|
||||
else:
|
||||
success = validator.validate_directory(path)
|
||||
|
||||
if args.strict and validator.warnings:
|
||||
print("Strict mode: treating warnings as errors", file=sys.stderr)
|
||||
success = False
|
||||
|
||||
return 0 if success else 1
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
97
.github/skills/security-scan-go-vuln-scripts/run.sh
vendored
Executable file
97
.github/skills/security-scan-go-vuln-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,97 @@
|
||||
#!/usr/bin/env bash
|
||||
# Security Scan Go Vulnerability - Execution Script
|
||||
#
|
||||
# This script wraps the Go vulnerability checker (govulncheck) to detect
|
||||
# known vulnerabilities in Go code and dependencies.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_go_environment "1.23" || error_exit "Go 1.23+ is required"
|
||||
|
||||
# Set defaults
|
||||
set_default_env "GOVULNCHECK_FORMAT" "text"
|
||||
|
||||
# Parse arguments
|
||||
FORMAT="${1:-${GOVULNCHECK_FORMAT}}"
|
||||
MODE="${2:-source}"
|
||||
|
||||
# Validate format
|
||||
case "${FORMAT}" in
|
||||
text|json|sarif)
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid format: ${FORMAT}. Must be one of: text, json, sarif"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Validate mode
|
||||
case "${MODE}" in
|
||||
source|binary)
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid mode: ${MODE}. Must be one of: source, binary"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Change to backend directory
|
||||
cd "${PROJECT_ROOT}/backend"
|
||||
|
||||
# Check for go.mod
|
||||
if [[ ! -f "go.mod" ]]; then
|
||||
log_error "go.mod not found in backend directory"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Execute govulncheck
|
||||
log_step "SCANNING" "Running Go vulnerability check"
|
||||
log_info "Format: ${FORMAT}"
|
||||
log_info "Mode: ${MODE}"
|
||||
log_info "Working directory: $(pwd)"
|
||||
|
||||
# Build govulncheck command
|
||||
GOVULNCHECK_CMD="go run golang.org/x/vuln/cmd/govulncheck@latest"
|
||||
|
||||
# Add format flag if not text (text is default)
|
||||
if [[ "${FORMAT}" != "text" ]]; then
|
||||
GOVULNCHECK_CMD="${GOVULNCHECK_CMD} -format=${FORMAT}"
|
||||
fi
|
||||
|
||||
# Add mode flag if not source (source is default)
|
||||
if [[ "${MODE}" != "source" ]]; then
|
||||
GOVULNCHECK_CMD="${GOVULNCHECK_CMD} -mode=${MODE}"
|
||||
fi
|
||||
|
||||
# Add target (all packages)
|
||||
GOVULNCHECK_CMD="${GOVULNCHECK_CMD} ./..."
|
||||
|
||||
# Execute the scan
|
||||
if eval "${GOVULNCHECK_CMD}"; then
|
||||
log_success "No vulnerabilities found"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
if [[ ${exit_code} -eq 3 ]]; then
|
||||
log_error "Vulnerabilities detected (exit code 3)"
|
||||
log_info "Review the output above for details and remediation advice"
|
||||
else
|
||||
log_error "Vulnerability scan failed with exit code: ${exit_code}"
|
||||
fi
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
280
.github/skills/security-scan-go-vuln.SKILL.md
vendored
Normal file
280
.github/skills/security-scan-go-vuln.SKILL.md
vendored
Normal file
@@ -0,0 +1,280 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "security-scan-go-vuln"
|
||||
version: "1.0.0"
|
||||
description: "Run Go vulnerability checker (govulncheck) to detect known vulnerabilities in Go code"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "security"
|
||||
- "vulnerabilities"
|
||||
- "go"
|
||||
- "govulncheck"
|
||||
- "scanning"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "go"
|
||||
version: ">=1.23"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "GOVULNCHECK_FORMAT"
|
||||
description: "Output format (text, json, sarif)"
|
||||
default: "text"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "format"
|
||||
type: "string"
|
||||
description: "Output format (text, json, sarif)"
|
||||
default: "text"
|
||||
required: false
|
||||
- name: "mode"
|
||||
type: "string"
|
||||
description: "Scan mode (source or binary)"
|
||||
default: "source"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "vulnerability_report"
|
||||
type: "stdout"
|
||||
description: "List of detected vulnerabilities with remediation advice"
|
||||
- name: "exit_code"
|
||||
type: "number"
|
||||
description: "0 if no vulnerabilities found, 3 if vulnerabilities detected"
|
||||
metadata:
|
||||
category: "security"
|
||||
subcategory: "vulnerability"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Security Scan Go Vulnerability
|
||||
|
||||
## Overview
|
||||
|
||||
Executes `govulncheck` from the official Go vulnerability database to scan Go code and dependencies for known security vulnerabilities. This tool analyzes both direct and transitive dependencies, providing actionable remediation advice.
|
||||
|
||||
This skill is designed for CI/CD pipelines and pre-release security validation.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.23 or higher installed and in PATH
|
||||
- Internet connection (for vulnerability database access)
|
||||
- Go module dependencies downloaded (`go mod download`)
|
||||
- Valid Go project with `go.mod` file
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run with default settings (text output, source mode):
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln
|
||||
```
|
||||
|
||||
### JSON Output
|
||||
|
||||
Get results in JSON format for parsing:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln json
|
||||
```
|
||||
|
||||
### SARIF Output
|
||||
|
||||
Get results in SARIF format for GitHub Code Scanning:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln sarif
|
||||
```
|
||||
|
||||
### Custom Format via Environment
|
||||
|
||||
```bash
|
||||
GOVULNCHECK_FORMAT=json .github/skills/scripts/skill-runner.sh security-scan-go-vuln
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| format | string | No | text | Output format (text, json, sarif) |
|
||||
| mode | string | No | source | Scan mode (source or binary) |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| GOVULNCHECK_FORMAT | No | text | Output format override |
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 (no vulnerabilities found)
|
||||
- **Error Exit Codes**:
|
||||
- 1: Scan error or invalid arguments
|
||||
- 3: Vulnerabilities detected
|
||||
- **Output**: Vulnerability report to stdout
|
||||
|
||||
## Vulnerability Report Format
|
||||
|
||||
### Text Output (Default)
|
||||
|
||||
```
|
||||
Scanning for dependencies with known vulnerabilities...
|
||||
No vulnerabilities found.
|
||||
```
|
||||
|
||||
Or if vulnerabilities are found:
|
||||
|
||||
```
|
||||
Found 2 vulnerabilities in dependencies
|
||||
|
||||
Vulnerability #1: GO-2023-1234
|
||||
Package: github.com/example/vulnerable
|
||||
Version: v1.2.3
|
||||
Description: Buffer overflow in Parse function
|
||||
Fixed in: v1.2.4
|
||||
More info: https://vuln.go.dev/GO-2023-1234
|
||||
|
||||
Vulnerability #2: GO-2023-5678
|
||||
Package: golang.org/x/crypto/ssh
|
||||
Version: v0.1.0
|
||||
Description: Insecure default configuration
|
||||
Fixed in: v0.3.0
|
||||
More info: https://vuln.go.dev/GO-2023-5678
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Scan
|
||||
|
||||
```bash
|
||||
# Scan backend Go code for vulnerabilities
|
||||
cd backend
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
Scanning your code and 125 packages across 23 dependent modules for known vulnerabilities...
|
||||
No vulnerabilities found.
|
||||
```
|
||||
|
||||
### Example 2: JSON Output for CI/CD
|
||||
|
||||
```bash
|
||||
# Get JSON output for automated processing
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln json > vuln-report.json
|
||||
```
|
||||
|
||||
### Example 3: CI/CD Pipeline Integration
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Check Go Vulnerabilities
|
||||
run: .github/skills/scripts/skill-runner.sh security-scan-go-vuln
|
||||
working-directory: backend
|
||||
|
||||
- name: Upload SARIF Report
|
||||
if: always()
|
||||
run: |
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln sarif > results.sarif
|
||||
# Upload to GitHub Code Scanning
|
||||
```
|
||||
|
||||
### Example 4: Binary Mode Scan
|
||||
|
||||
```bash
|
||||
# Scan a compiled binary
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln text binary
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Go not installed**:
|
||||
```bash
|
||||
Error: Go 1.23+ is required
|
||||
Solution: Install Go 1.23 or higher
|
||||
```
|
||||
|
||||
**Network unavailable**:
|
||||
```bash
|
||||
Error: Failed to fetch vulnerability database
|
||||
Solution: Check internet connection or proxy settings
|
||||
```
|
||||
|
||||
**Vulnerabilities found**:
|
||||
```bash
|
||||
Exit code: 3
|
||||
Solution: Review vulnerabilities and update affected packages
|
||||
```
|
||||
|
||||
**Module not found**:
|
||||
```bash
|
||||
Error: go.mod file not found
|
||||
Solution: Run from a valid Go module directory
|
||||
```
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- **0**: No vulnerabilities found
|
||||
- **1**: Scan error or invalid arguments
|
||||
- **3**: Vulnerabilities detected (standard govulncheck exit code)
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [security-scan-trivy](./security-scan-trivy.SKILL.md) - Multi-language vulnerability scanning
|
||||
- [test-backend-coverage](./test-backend-coverage.SKILL.md) - Backend test coverage
|
||||
|
||||
## Notes
|
||||
|
||||
- `govulncheck` uses the official Go vulnerability database at https://vuln.go.dev
|
||||
- Database is automatically updated during each scan
|
||||
- Only checks vulnerabilities that are reachable from your code
|
||||
- Does not require building the code (analyzes source)
|
||||
- Can also scan compiled binaries with `--mode=binary`
|
||||
- Results may change as new vulnerabilities are published
|
||||
- Recommended to run before each release and in CI/CD
|
||||
- Zero false positives (only reports known CVEs)
|
||||
|
||||
## Remediation Workflow
|
||||
|
||||
When vulnerabilities are found:
|
||||
|
||||
1. **Review the Report**: Understand which packages are affected
|
||||
2. **Check Fix Availability**: Look for fixed versions in the report
|
||||
3. **Update Dependencies**: Run `go get -u` to update affected packages
|
||||
4. **Re-run Scan**: Verify vulnerabilities are resolved
|
||||
5. **Test**: Run full test suite after updates
|
||||
6. **Document**: Note any unresolvable vulnerabilities in security log
|
||||
|
||||
## Integration with GitHub Security
|
||||
|
||||
For SARIF output integration with GitHub Code Scanning:
|
||||
|
||||
```bash
|
||||
# Generate SARIF report
|
||||
.github/skills/scripts/skill-runner.sh security-scan-go-vuln sarif > govulncheck.sarif
|
||||
|
||||
# Upload to GitHub (requires GitHub CLI)
|
||||
gh api /repos/:owner/:repo/code-scanning/sarifs \
|
||||
-F sarif=@govulncheck.sarif \
|
||||
-F commit_sha=$GITHUB_SHA \
|
||||
-F ref=$GITHUB_REF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: `go run golang.org/x/vuln/cmd/govulncheck@latest`
|
||||
86
.github/skills/security-scan-trivy-scripts/run.sh
vendored
Executable file
86
.github/skills/security-scan-trivy-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,86 @@
|
||||
#!/usr/bin/env bash
|
||||
# Security Scan Trivy - Execution Script
|
||||
#
|
||||
# This script wraps the Trivy Docker command to scan for vulnerabilities,
|
||||
# secrets, and misconfigurations.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_docker_environment || error_exit "Docker is required but not available"
|
||||
|
||||
# Set defaults
|
||||
set_default_env "TRIVY_SEVERITY" "CRITICAL,HIGH,MEDIUM"
|
||||
set_default_env "TRIVY_TIMEOUT" "10m"
|
||||
|
||||
# Parse arguments
|
||||
SCANNERS="${1:-vuln,secret,misconfig}"
|
||||
FORMAT="${2:-table}"
|
||||
|
||||
# Validate format
|
||||
case "${FORMAT}" in
|
||||
table|json|sarif)
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid format: ${FORMAT}. Must be one of: table, json, sarif"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
|
||||
# Validate scanners
|
||||
IFS=',' read -ra SCANNER_ARRAY <<< "${SCANNERS}"
|
||||
for scanner in "${SCANNER_ARRAY[@]}"; do
|
||||
case "${scanner}" in
|
||||
vuln|secret|misconfig)
|
||||
;;
|
||||
*)
|
||||
log_error "Invalid scanner: ${scanner}. Must be one of: vuln, secret, misconfig"
|
||||
exit 2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Execute Trivy scan
|
||||
log_step "SCANNING" "Running Trivy security scan"
|
||||
log_info "Scanners: ${SCANNERS}"
|
||||
log_info "Format: ${FORMAT}"
|
||||
log_info "Severity: ${TRIVY_SEVERITY}"
|
||||
log_info "Timeout: ${TRIVY_TIMEOUT}"
|
||||
|
||||
cd "${PROJECT_ROOT}"
|
||||
|
||||
# Run Trivy via Docker
|
||||
if docker run --rm \
|
||||
-v "$(pwd):/app:ro" \
|
||||
-e "TRIVY_SEVERITY=${TRIVY_SEVERITY}" \
|
||||
-e "TRIVY_TIMEOUT=${TRIVY_TIMEOUT}" \
|
||||
aquasec/trivy:latest \
|
||||
fs \
|
||||
--scanners "${SCANNERS}" \
|
||||
--format "${FORMAT}" \
|
||||
/app; then
|
||||
log_success "Trivy scan completed - no issues found"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
if [[ ${exit_code} -eq 1 ]]; then
|
||||
log_error "Trivy scan found security issues"
|
||||
else
|
||||
log_error "Trivy scan failed with exit code: ${exit_code}"
|
||||
fi
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
253
.github/skills/security-scan-trivy.SKILL.md
vendored
Normal file
253
.github/skills/security-scan-trivy.SKILL.md
vendored
Normal file
@@ -0,0 +1,253 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "security-scan-trivy"
|
||||
version: "1.0.0"
|
||||
description: "Run Trivy security scanner for vulnerabilities, secrets, and misconfigurations"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "security"
|
||||
- "scanning"
|
||||
- "trivy"
|
||||
- "vulnerabilities"
|
||||
- "secrets"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "docker"
|
||||
version: ">=24.0"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "TRIVY_SEVERITY"
|
||||
description: "Comma-separated list of severities to scan for"
|
||||
default: "CRITICAL,HIGH,MEDIUM"
|
||||
required: false
|
||||
- name: "TRIVY_TIMEOUT"
|
||||
description: "Timeout for Trivy scan"
|
||||
default: "10m"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "scanners"
|
||||
type: "string"
|
||||
description: "Comma-separated list of scanners (vuln, secret, misconfig)"
|
||||
default: "vuln,secret,misconfig"
|
||||
required: false
|
||||
- name: "format"
|
||||
type: "string"
|
||||
description: "Output format (table, json, sarif)"
|
||||
default: "table"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "scan_results"
|
||||
type: "stdout"
|
||||
description: "Trivy scan results in specified format"
|
||||
- name: "exit_code"
|
||||
type: "number"
|
||||
description: "0 if no issues found, non-zero otherwise"
|
||||
metadata:
|
||||
category: "security"
|
||||
subcategory: "scan"
|
||||
execution_time: "medium"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Security Scan Trivy
|
||||
|
||||
## Overview
|
||||
|
||||
Executes Trivy security scanner using Docker to scan the project for vulnerabilities, secrets, and misconfigurations. Trivy scans filesystem, dependencies, and configuration files to identify security issues.
|
||||
|
||||
This skill is designed for CI/CD pipelines and local security validation before commits.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Docker 24.0 or higher installed and running
|
||||
- Internet connection (for vulnerability database updates)
|
||||
- Read permissions for project directory
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run with default settings (all scanners, table format):
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh security-scan-trivy
|
||||
```
|
||||
|
||||
### Custom Scanners
|
||||
|
||||
Scan only for vulnerabilities:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh security-scan-trivy vuln
|
||||
```
|
||||
|
||||
Scan for secrets and misconfigurations:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh security-scan-trivy secret,misconfig
|
||||
```
|
||||
|
||||
### Custom Severity
|
||||
|
||||
Scan only for critical and high severity issues:
|
||||
|
||||
```bash
|
||||
TRIVY_SEVERITY=CRITICAL,HIGH .github/skills/scripts/skill-runner.sh security-scan-trivy
|
||||
```
|
||||
|
||||
### JSON Output
|
||||
|
||||
Get results in JSON format for parsing:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh security-scan-trivy vuln,secret,misconfig json
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| scanners | string | No | vuln,secret,misconfig | Comma-separated list of scanners to run |
|
||||
| format | string | No | table | Output format (table, json, sarif) |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| TRIVY_SEVERITY | No | CRITICAL,HIGH,MEDIUM | Severities to report |
|
||||
| TRIVY_TIMEOUT | No | 10m | Maximum scan duration |
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 (no issues found)
|
||||
- **Error Exit Codes**:
|
||||
- 1: Issues found
|
||||
- 2: Scanner error
|
||||
- **Output**: Scan results to stdout in specified format
|
||||
|
||||
## Scanner Types
|
||||
|
||||
### Vulnerability Scanner (vuln)
|
||||
Scans for known CVEs in:
|
||||
- Go dependencies (go.mod)
|
||||
- npm packages (package.json)
|
||||
- Docker base images (Dockerfile)
|
||||
|
||||
### Secret Scanner (secret)
|
||||
Detects exposed secrets:
|
||||
- API keys
|
||||
- Passwords
|
||||
- Tokens
|
||||
- Private keys
|
||||
|
||||
### Misconfiguration Scanner (misconfig)
|
||||
Checks configuration files:
|
||||
- Dockerfile best practices
|
||||
- Kubernetes manifests
|
||||
- Terraform files
|
||||
- Docker Compose files
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Full Scan with Table Output
|
||||
|
||||
```bash
|
||||
# Scan all vulnerability types, display as table
|
||||
.github/skills/scripts/skill-runner.sh security-scan-trivy
|
||||
```
|
||||
|
||||
Output:
|
||||
```
|
||||
2025-12-20T10:00:00Z INFO Trivy version: 0.48.0
|
||||
2025-12-20T10:00:01Z INFO Scanning filesystem...
|
||||
Total: 0 (CRITICAL: 0, HIGH: 0, MEDIUM: 0)
|
||||
```
|
||||
|
||||
### Example 2: Vulnerability Scan Only (JSON)
|
||||
|
||||
```bash
|
||||
# Scan for vulnerabilities only, output as JSON
|
||||
.github/skills/scripts/skill-runner.sh security-scan-trivy vuln json > trivy-results.json
|
||||
```
|
||||
|
||||
### Example 3: Critical Issues Only
|
||||
|
||||
```bash
|
||||
# Scan for critical severity issues only
|
||||
TRIVY_SEVERITY=CRITICAL .github/skills/scripts/skill-runner.sh security-scan-trivy
|
||||
```
|
||||
|
||||
### Example 4: CI/CD Pipeline Integration
|
||||
|
||||
```yaml
|
||||
# GitHub Actions example
|
||||
- name: Run Trivy Security Scan
|
||||
run: .github/skills/scripts/skill-runner.sh security-scan-trivy
|
||||
continue-on-error: false
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Docker not running**:
|
||||
```bash
|
||||
Error: Cannot connect to Docker daemon
|
||||
Solution: Start Docker service
|
||||
```
|
||||
|
||||
**Network timeout**:
|
||||
```bash
|
||||
Error: Failed to download vulnerability database
|
||||
Solution: Increase TRIVY_TIMEOUT or check internet connection
|
||||
```
|
||||
|
||||
**Vulnerabilities found**:
|
||||
```bash
|
||||
Exit code: 1
|
||||
Solution: Review and remediate reported vulnerabilities
|
||||
```
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- **0**: No security issues found
|
||||
- **1**: Security issues detected
|
||||
- **2**: Scanner error or invalid arguments
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [security-scan-go-vuln](./security-scan-go-vuln.SKILL.md) - Go-specific vulnerability checking
|
||||
- [qa-precommit-all](./qa-precommit-all.SKILL.md) - Pre-commit quality checks
|
||||
|
||||
## Notes
|
||||
|
||||
- Trivy automatically updates its vulnerability database on each run
|
||||
- Scan results may vary based on database version
|
||||
- Some vulnerabilities may have no fix available yet
|
||||
- Consider using `.trivyignore` file to suppress false positives
|
||||
- Recommended to run before each release
|
||||
- Network access required for first run and database updates
|
||||
|
||||
## Security Thresholds
|
||||
|
||||
**Project Standards**:
|
||||
- **CRITICAL**: Must fix before release (blocking)
|
||||
- **HIGH**: Should fix before release (warning)
|
||||
- **MEDIUM**: Fix in next release cycle (informational)
|
||||
- **LOW**: Optional, fix as time permits
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: Docker inline command (Trivy)
|
||||
55
.github/skills/test-backend-coverage-scripts/run.sh
vendored
Executable file
55
.github/skills/test-backend-coverage-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test Backend Coverage - Execution Script
|
||||
#
|
||||
# This script wraps the legacy go-test-coverage.sh script while providing
|
||||
# the Agent Skills interface and logging.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# Helper scripts are in .github/skills/scripts/
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
# Project root is 3 levels up from this script (skills/skill-name-scripts/run.sh -> project root)
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_go_environment "1.23" || error_exit "Go 1.23+ is required"
|
||||
validate_python_environment "3.8" || error_exit "Python 3.8+ is required"
|
||||
|
||||
# Validate project structure
|
||||
log_step "VALIDATION" "Checking project structure"
|
||||
cd "${PROJECT_ROOT}"
|
||||
validate_project_structure "backend" "scripts/go-test-coverage.sh" || error_exit "Invalid project structure"
|
||||
|
||||
# Set default environment variables
|
||||
set_default_env "CHARON_MIN_COVERAGE" "85"
|
||||
set_default_env "PERF_MAX_MS_GETSTATUS_P95" "25ms"
|
||||
set_default_env "PERF_MAX_MS_GETSTATUS_P95_PARALLEL" "50ms"
|
||||
set_default_env "PERF_MAX_MS_LISTDECISIONS_P95" "75ms"
|
||||
|
||||
# Execute the legacy script
|
||||
log_step "EXECUTION" "Running backend tests with coverage"
|
||||
log_info "Minimum coverage: ${CHARON_MIN_COVERAGE}%"
|
||||
|
||||
LEGACY_SCRIPT="${PROJECT_ROOT}/scripts/go-test-coverage.sh"
|
||||
check_file_exists "${LEGACY_SCRIPT}"
|
||||
|
||||
# Execute with proper error handling
|
||||
if "${LEGACY_SCRIPT}" "$@"; then
|
||||
log_success "Backend coverage tests passed"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
log_error "Backend coverage tests failed (exit code: ${exit_code})"
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
212
.github/skills/test-backend-coverage.SKILL.md
vendored
Normal file
212
.github/skills/test-backend-coverage.SKILL.md
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "test-backend-coverage"
|
||||
version: "1.0.0"
|
||||
description: "Run Go backend tests with coverage analysis and threshold validation (minimum 85%)"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "testing"
|
||||
- "coverage"
|
||||
- "go"
|
||||
- "backend"
|
||||
- "validation"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "go"
|
||||
version: ">=1.23"
|
||||
optional: false
|
||||
- name: "python3"
|
||||
version: ">=3.8"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "CHARON_MIN_COVERAGE"
|
||||
description: "Minimum coverage percentage required (overrides default)"
|
||||
default: "85"
|
||||
required: false
|
||||
- name: "CPM_MIN_COVERAGE"
|
||||
description: "Alternative name for minimum coverage threshold (legacy)"
|
||||
default: "85"
|
||||
required: false
|
||||
- name: "PERF_MAX_MS_GETSTATUS_P95"
|
||||
description: "Maximum P95 latency for GetStatus endpoint (ms)"
|
||||
default: "25ms"
|
||||
required: false
|
||||
- name: "PERF_MAX_MS_GETSTATUS_P95_PARALLEL"
|
||||
description: "Maximum P95 latency for parallel GetStatus calls (ms)"
|
||||
default: "50ms"
|
||||
required: false
|
||||
- name: "PERF_MAX_MS_LISTDECISIONS_P95"
|
||||
description: "Maximum P95 latency for ListDecisions endpoint (ms)"
|
||||
default: "75ms"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose test output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "coverage.txt"
|
||||
type: "file"
|
||||
description: "Go coverage profile in text format"
|
||||
path: "backend/coverage.txt"
|
||||
- name: "coverage_summary"
|
||||
type: "stdout"
|
||||
description: "Summary of coverage statistics and validation result"
|
||||
metadata:
|
||||
category: "test"
|
||||
subcategory: "coverage"
|
||||
execution_time: "medium"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Test Backend Coverage
|
||||
|
||||
## Overview
|
||||
|
||||
Executes the Go backend test suite with race detection enabled, generates a coverage profile, filters excluded packages, and validates that the total coverage meets or exceeds the configured threshold (default: 85%).
|
||||
|
||||
This skill is designed for continuous integration and pre-commit hooks to ensure code quality standards are maintained.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.23 or higher installed and in PATH
|
||||
- Python 3.8 or higher installed and in PATH
|
||||
- Backend dependencies installed (`cd backend && go mod download`)
|
||||
- Write permissions in `backend/` directory (for coverage.txt)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run with default settings (85% minimum coverage):
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
### Custom Coverage Threshold
|
||||
|
||||
Set a custom minimum coverage percentage:
|
||||
|
||||
```bash
|
||||
export CHARON_MIN_COVERAGE=90
|
||||
.github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions or other CI/CD pipelines:
|
||||
|
||||
```yaml
|
||||
- name: Run Backend Tests with Coverage
|
||||
run: .github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
env:
|
||||
CHARON_MIN_COVERAGE: 85
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose test output (-v flag) |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| CHARON_MIN_COVERAGE | No | 85 | Minimum coverage percentage required for success |
|
||||
| CPM_MIN_COVERAGE | No | 85 | Legacy name for minimum coverage (fallback) |
|
||||
| PERF_MAX_MS_GETSTATUS_P95 | No | 25ms | Max P95 latency for GetStatus endpoint |
|
||||
| PERF_MAX_MS_GETSTATUS_P95_PARALLEL | No | 50ms | Max P95 latency for parallel GetStatus |
|
||||
| PERF_MAX_MS_LISTDECISIONS_P95 | No | 75ms | Max P95 latency for ListDecisions endpoint |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All tests passed and coverage meets threshold
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: Coverage below threshold or coverage file generation failed
|
||||
- **Non-zero**: Tests failed or other error occurred
|
||||
|
||||
### Output Files
|
||||
- **backend/coverage.txt**: Go coverage profile (text format)
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
Filtering excluded packages from coverage report...
|
||||
Coverage filtering complete
|
||||
total: (statements) 87.4%
|
||||
Computed coverage: 87.4% (minimum required 85%)
|
||||
Coverage requirement met
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
### Example 2: Higher Coverage Threshold
|
||||
|
||||
```bash
|
||||
export CHARON_MIN_COVERAGE=90
|
||||
.github/skills/scripts/skill-runner.sh test-backend-coverage
|
||||
```
|
||||
|
||||
## Excluded Packages
|
||||
|
||||
The following packages are excluded from coverage analysis:
|
||||
- `github.com/Wikid82/charon/backend/cmd/api` - API server entrypoint
|
||||
- `github.com/Wikid82/charon/backend/cmd/seed` - Database seeding tool
|
||||
- `github.com/Wikid82/charon/backend/internal/logger` - Logging infrastructure
|
||||
- `github.com/Wikid82/charon/backend/internal/metrics` - Metrics infrastructure
|
||||
- `github.com/Wikid82/charon/backend/internal/trace` - Tracing infrastructure
|
||||
- `github.com/Wikid82/charon/backend/integration` - Integration test utilities
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: coverage file not generated by go test
|
||||
**Solution**: Review test output for failures; fix failing tests
|
||||
|
||||
#### Error: go tool cover failed or timed out
|
||||
**Solution**: Clear Go cache and re-run tests
|
||||
|
||||
#### Error: Coverage X% is below required Y%
|
||||
**Solution**: Add tests for uncovered code paths or adjust threshold
|
||||
|
||||
## Related Skills
|
||||
|
||||
- test-backend-unit - Fast unit tests without coverage
|
||||
- security-check-govulncheck - Go vulnerability scanning
|
||||
- utility-cache-clear-go - Clear Go build cache
|
||||
|
||||
## Notes
|
||||
|
||||
- **Race Detection**: Always runs with `-race` flag enabled (adds ~30% overhead)
|
||||
- **Coverage Filtering**: Excluded packages are defined in the script itself
|
||||
- **Python Dependency**: Uses Python for decimal-precision coverage comparison
|
||||
- **Timeout Protection**: Coverage generation has a 60-second timeout
|
||||
- **Idempotency**: Safe to run multiple times; cleans up old coverage files
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/go-test-coverage.sh`
|
||||
47
.github/skills/test-backend-unit-scripts/run.sh
vendored
Executable file
47
.github/skills/test-backend-unit-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test Backend Unit - Execution Script
|
||||
#
|
||||
# This script runs Go backend unit tests without coverage analysis,
|
||||
# providing fast test execution for development workflows.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# Helper scripts are in .github/skills/scripts/
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
# Project root is 3 levels up from this script (skills/skill-name-scripts/run.sh -> project root)
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_go_environment "1.23" || error_exit "Go 1.23+ is required"
|
||||
|
||||
# Validate project structure
|
||||
log_step "VALIDATION" "Checking project structure"
|
||||
cd "${PROJECT_ROOT}"
|
||||
validate_project_structure "backend" || error_exit "Invalid project structure"
|
||||
|
||||
# Change to backend directory
|
||||
cd "${PROJECT_ROOT}/backend"
|
||||
|
||||
# Execute tests
|
||||
log_step "EXECUTION" "Running backend unit tests"
|
||||
|
||||
# Run go test with all passed arguments
|
||||
if go test "$@" ./...; then
|
||||
log_success "Backend unit tests passed"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
log_error "Backend unit tests failed (exit code: ${exit_code})"
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
191
.github/skills/test-backend-unit.SKILL.md
vendored
Normal file
191
.github/skills/test-backend-unit.SKILL.md
vendored
Normal file
@@ -0,0 +1,191 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "test-backend-unit"
|
||||
version: "1.0.0"
|
||||
description: "Run Go backend unit tests without coverage analysis (fast execution)"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "testing"
|
||||
- "unit-tests"
|
||||
- "go"
|
||||
- "backend"
|
||||
- "fast"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "go"
|
||||
version: ">=1.23"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose test output"
|
||||
default: "false"
|
||||
required: false
|
||||
- name: "package"
|
||||
type: "string"
|
||||
description: "Specific package to test (e.g., ./internal/...)"
|
||||
default: "./..."
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "Go test output showing pass/fail status"
|
||||
metadata:
|
||||
category: "test"
|
||||
subcategory: "unit"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Test Backend Unit
|
||||
|
||||
## Overview
|
||||
|
||||
Executes the Go backend unit test suite without coverage analysis. This skill provides fast test execution for quick feedback during development, making it ideal for pre-commit checks and rapid iteration.
|
||||
|
||||
Unlike test-backend-coverage, this skill does not generate coverage reports or enforce coverage thresholds, focusing purely on test pass/fail status.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go 1.23 or higher installed and in PATH
|
||||
- Backend dependencies installed (`cd backend && go mod download`)
|
||||
- Sufficient disk space for test artifacts
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run all backend unit tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit
|
||||
```
|
||||
|
||||
### Test Specific Package
|
||||
|
||||
Test only a specific package or module:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit -- ./internal/handlers/...
|
||||
```
|
||||
|
||||
### Verbose Output
|
||||
|
||||
Enable verbose test output for debugging:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit -- -v
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions or other CI/CD pipelines:
|
||||
|
||||
```yaml
|
||||
- name: Run Backend Unit Tests
|
||||
run: .github/skills/scripts/skill-runner.sh test-backend-unit
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose test output (-v flag) |
|
||||
| package | string | No | ./... | Package pattern to test |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
No environment variables are required for this skill.
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All tests passed
|
||||
|
||||
### Error Exit Codes
|
||||
- **Non-zero**: One or more tests failed
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
ok github.com/Wikid82/charon/backend/internal/handlers 0.523s
|
||||
ok github.com/Wikid82/charon/backend/internal/models 0.189s
|
||||
ok github.com/Wikid82/charon/backend/internal/services 0.742s
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit
|
||||
```
|
||||
|
||||
### Example 2: Test Specific Package
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit -- ./internal/handlers
|
||||
```
|
||||
|
||||
### Example 3: Verbose Output
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit -- -v
|
||||
```
|
||||
|
||||
### Example 4: Run with Race Detection
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit -- -race
|
||||
```
|
||||
|
||||
### Example 5: Short Mode (Skip Long Tests)
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-backend-unit -- -short
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: package not found
|
||||
**Solution**: Verify package path is correct; run `go list ./...` to see available packages
|
||||
|
||||
#### Error: build failed
|
||||
**Solution**: Fix compilation errors; run `go build ./...` to identify issues
|
||||
|
||||
#### Error: test timeout
|
||||
**Solution**: Increase timeout with `-timeout` flag or fix hanging tests
|
||||
|
||||
## Related Skills
|
||||
|
||||
- test-backend-coverage - Run tests with coverage analysis (slower)
|
||||
- build-check-go - Verify Go builds without running tests
|
||||
- security-check-govulncheck - Go vulnerability scanning
|
||||
|
||||
## Notes
|
||||
|
||||
- **Execution Time**: Fast execution (~5-10 seconds typical)
|
||||
- **No Coverage**: Does not generate coverage reports
|
||||
- **Race Detection**: Not enabled by default (unlike test-backend-coverage)
|
||||
- **Idempotency**: Safe to run multiple times
|
||||
- **Caching**: Benefits from Go test cache for unchanged packages
|
||||
- **Suitable For**: Pre-commit hooks, quick feedback, TDD workflows
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: Inline task command
|
||||
52
.github/skills/test-frontend-coverage-scripts/run.sh
vendored
Executable file
52
.github/skills/test-frontend-coverage-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,52 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test Frontend Coverage - Execution Script
|
||||
#
|
||||
# This script wraps the legacy frontend-test-coverage.sh script while providing
|
||||
# the Agent Skills interface and logging.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# Helper scripts are in .github/skills/scripts/
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
# Project root is 3 levels up from this script (skills/skill-name-scripts/run.sh -> project root)
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_node_environment "18.0" || error_exit "Node.js 18.0+ is required"
|
||||
validate_python_environment "3.8" || error_exit "Python 3.8+ is required"
|
||||
|
||||
# Validate project structure
|
||||
log_step "VALIDATION" "Checking project structure"
|
||||
cd "${PROJECT_ROOT}"
|
||||
validate_project_structure "frontend" "scripts/frontend-test-coverage.sh" || error_exit "Invalid project structure"
|
||||
|
||||
# Set default environment variables
|
||||
set_default_env "CHARON_MIN_COVERAGE" "85"
|
||||
|
||||
# Execute the legacy script
|
||||
log_step "EXECUTION" "Running frontend tests with coverage"
|
||||
log_info "Minimum coverage: ${CHARON_MIN_COVERAGE}%"
|
||||
|
||||
LEGACY_SCRIPT="${PROJECT_ROOT}/scripts/frontend-test-coverage.sh"
|
||||
check_file_exists "${LEGACY_SCRIPT}"
|
||||
|
||||
# Execute with proper error handling
|
||||
if "${LEGACY_SCRIPT}" "$@"; then
|
||||
log_success "Frontend coverage tests passed"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
log_error "Frontend coverage tests failed (exit code: ${exit_code})"
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
197
.github/skills/test-frontend-coverage.SKILL.md
vendored
Normal file
197
.github/skills/test-frontend-coverage.SKILL.md
vendored
Normal file
@@ -0,0 +1,197 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "test-frontend-coverage"
|
||||
version: "1.0.0"
|
||||
description: "Run frontend tests with coverage analysis and threshold validation (minimum 85%)"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "testing"
|
||||
- "coverage"
|
||||
- "frontend"
|
||||
- "vitest"
|
||||
- "validation"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "node"
|
||||
version: ">=18.0"
|
||||
optional: false
|
||||
- name: "npm"
|
||||
version: ">=9.0"
|
||||
optional: false
|
||||
- name: "python3"
|
||||
version: ">=3.8"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "CHARON_MIN_COVERAGE"
|
||||
description: "Minimum coverage percentage required (overrides default)"
|
||||
default: "85"
|
||||
required: false
|
||||
- name: "CPM_MIN_COVERAGE"
|
||||
description: "Alternative name for minimum coverage threshold (legacy)"
|
||||
default: "85"
|
||||
required: false
|
||||
parameters:
|
||||
- name: "verbose"
|
||||
type: "boolean"
|
||||
description: "Enable verbose test output"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "coverage-summary.json"
|
||||
type: "file"
|
||||
description: "JSON coverage summary generated by Vitest"
|
||||
path: "frontend/coverage/coverage-summary.json"
|
||||
- name: "coverage_summary"
|
||||
type: "stdout"
|
||||
description: "Summary of coverage statistics and validation result"
|
||||
metadata:
|
||||
category: "test"
|
||||
subcategory: "coverage"
|
||||
execution_time: "medium"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Test Frontend Coverage
|
||||
|
||||
## Overview
|
||||
|
||||
Executes the frontend test suite using Vitest with coverage enabled, generates a JSON coverage summary, and validates that the total statements coverage meets or exceeds the configured threshold (default: 85%).
|
||||
|
||||
This skill is designed for continuous integration and pre-commit hooks to ensure code quality standards are maintained.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 18.0 or higher installed and in PATH
|
||||
- npm 9.0 or higher installed and in PATH
|
||||
- Python 3.8 or higher installed and in PATH
|
||||
- Frontend dependencies installed (`cd frontend && npm install`)
|
||||
- Write permissions in `frontend/coverage/` directory
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run with default settings (85% minimum coverage):
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-coverage
|
||||
```
|
||||
|
||||
### Custom Coverage Threshold
|
||||
|
||||
Set a custom minimum coverage percentage:
|
||||
|
||||
```bash
|
||||
export CHARON_MIN_COVERAGE=90
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-coverage
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions or other CI/CD pipelines:
|
||||
|
||||
```yaml
|
||||
- name: Run Frontend Tests with Coverage
|
||||
run: .github/skills/scripts/skill-runner.sh test-frontend-coverage
|
||||
env:
|
||||
CHARON_MIN_COVERAGE: 85
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| verbose | boolean | No | false | Enable verbose test output |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| CHARON_MIN_COVERAGE | No | 85 | Minimum coverage percentage required for success |
|
||||
| CPM_MIN_COVERAGE | No | 85 | Legacy name for minimum coverage (fallback) |
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All tests passed and coverage meets threshold
|
||||
|
||||
### Error Exit Codes
|
||||
- **1**: Coverage below threshold or coverage file generation failed
|
||||
- **Non-zero**: Tests failed or other error occurred
|
||||
|
||||
### Output Files
|
||||
- **frontend/coverage/coverage-summary.json**: Vitest coverage summary (JSON format)
|
||||
- **frontend/coverage/index.html**: HTML coverage report (viewable in browser)
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
Computed frontend coverage: 87.5% (minimum required 85%)
|
||||
Frontend coverage requirement met
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-coverage
|
||||
```
|
||||
|
||||
### Example 2: Higher Coverage Threshold
|
||||
|
||||
```bash
|
||||
export CHARON_MIN_COVERAGE=90
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-coverage
|
||||
```
|
||||
|
||||
### Example 3: View HTML Coverage Report
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-coverage
|
||||
open frontend/coverage/index.html # macOS
|
||||
xdg-open frontend/coverage/index.html # Linux
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: Coverage summary file not found
|
||||
**Solution**: Check that Vitest is configured with `--coverage` and `--reporter=json-summary`
|
||||
|
||||
#### Error: Frontend coverage X% is below required Y%
|
||||
**Solution**: Add tests for uncovered components or adjust threshold
|
||||
|
||||
#### Error: npm ci failed
|
||||
**Solution**: Clear node_modules and package-lock.json, then reinstall dependencies
|
||||
|
||||
## Related Skills
|
||||
|
||||
- test-frontend-unit - Fast unit tests without coverage
|
||||
- test-backend-coverage - Backend Go coverage tests
|
||||
- utility-cache-clear-go - Clear build caches
|
||||
|
||||
## Notes
|
||||
|
||||
- **Vitest Configuration**: Uses istanbul coverage provider for JSON summary reports
|
||||
- **Coverage Directory**: Coverage artifacts are written to `frontend/coverage/`
|
||||
- **Python Dependency**: Uses Python for decimal-precision coverage comparison
|
||||
- **Idempotency**: Safe to run multiple times; cleans up old coverage files
|
||||
- **CI Mode**: Runs `npm ci` in CI environments to ensure clean installs
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: `scripts/frontend-test-coverage.sh`
|
||||
47
.github/skills/test-frontend-unit-scripts/run.sh
vendored
Executable file
47
.github/skills/test-frontend-unit-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/env bash
|
||||
# Test Frontend Unit - Execution Script
|
||||
#
|
||||
# This script runs frontend unit tests without coverage analysis,
|
||||
# providing fast test execution for development workflows.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source helper scripts
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
# Helper scripts are in .github/skills/scripts/
|
||||
SKILLS_SCRIPTS_DIR="$(cd "${SCRIPT_DIR}/../scripts" && pwd)"
|
||||
|
||||
# shellcheck source=../scripts/_logging_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_logging_helpers.sh"
|
||||
# shellcheck source=../scripts/_error_handling_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_error_handling_helpers.sh"
|
||||
# shellcheck source=../scripts/_environment_helpers.sh
|
||||
source "${SKILLS_SCRIPTS_DIR}/_environment_helpers.sh"
|
||||
|
||||
# Project root is 3 levels up from this script (skills/skill-name-scripts/run.sh -> project root)
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
|
||||
|
||||
# Validate environment
|
||||
log_step "ENVIRONMENT" "Validating prerequisites"
|
||||
validate_node_environment "18.0" || error_exit "Node.js 18.0+ is required"
|
||||
|
||||
# Validate project structure
|
||||
log_step "VALIDATION" "Checking project structure"
|
||||
cd "${PROJECT_ROOT}"
|
||||
validate_project_structure "frontend" || error_exit "Invalid project structure"
|
||||
|
||||
# Change to frontend directory
|
||||
cd "${PROJECT_ROOT}/frontend"
|
||||
|
||||
# Execute tests
|
||||
log_step "EXECUTION" "Running frontend unit tests"
|
||||
|
||||
# Run npm test with all passed arguments
|
||||
if npm run test -- "$@"; then
|
||||
log_success "Frontend unit tests passed"
|
||||
exit 0
|
||||
else
|
||||
exit_code=$?
|
||||
log_error "Frontend unit tests failed (exit code: ${exit_code})"
|
||||
exit "${exit_code}"
|
||||
fi
|
||||
198
.github/skills/test-frontend-unit.SKILL.md
vendored
Normal file
198
.github/skills/test-frontend-unit.SKILL.md
vendored
Normal file
@@ -0,0 +1,198 @@
|
||||
---
|
||||
# agentskills.io specification v1.0
|
||||
name: "test-frontend-unit"
|
||||
version: "1.0.0"
|
||||
description: "Run frontend unit tests without coverage analysis (fast execution)"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "testing"
|
||||
- "unit-tests"
|
||||
- "frontend"
|
||||
- "vitest"
|
||||
- "fast"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "node"
|
||||
version: ">=18.0"
|
||||
optional: false
|
||||
- name: "npm"
|
||||
version: ">=9.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters:
|
||||
- name: "watch"
|
||||
type: "boolean"
|
||||
description: "Run tests in watch mode"
|
||||
default: "false"
|
||||
required: false
|
||||
- name: "filter"
|
||||
type: "string"
|
||||
description: "Filter tests by name pattern"
|
||||
default: ""
|
||||
required: false
|
||||
outputs:
|
||||
- name: "test_results"
|
||||
type: "stdout"
|
||||
description: "Vitest output showing pass/fail status"
|
||||
metadata:
|
||||
category: "test"
|
||||
subcategory: "unit"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Test Frontend Unit
|
||||
|
||||
## Overview
|
||||
|
||||
Executes the frontend unit test suite using Vitest without coverage analysis. This skill provides fast test execution for quick feedback during development, making it ideal for pre-commit checks and rapid iteration.
|
||||
|
||||
Unlike test-frontend-coverage, this skill does not generate coverage reports or enforce coverage thresholds, focusing purely on test pass/fail status.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Node.js 18.0 or higher installed and in PATH
|
||||
- npm 9.0 or higher installed and in PATH
|
||||
- Frontend dependencies installed (`cd frontend && npm install`)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
Run all frontend unit tests:
|
||||
|
||||
```bash
|
||||
cd /path/to/charon
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit
|
||||
```
|
||||
|
||||
### Watch Mode
|
||||
|
||||
Run tests in watch mode for continuous testing:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit -- --watch
|
||||
```
|
||||
|
||||
### Filter Tests
|
||||
|
||||
Run tests matching a specific pattern:
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit -- --grep "Button"
|
||||
```
|
||||
|
||||
### CI/CD Integration
|
||||
|
||||
For use in GitHub Actions or other CI/CD pipelines:
|
||||
|
||||
```yaml
|
||||
- name: Run Frontend Unit Tests
|
||||
run: .github/skills/scripts/skill-runner.sh test-frontend-unit
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| watch | boolean | No | false | Run tests in watch mode |
|
||||
| filter | string | No | "" | Filter tests by name pattern |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
No environment variables are required for this skill.
|
||||
|
||||
## Outputs
|
||||
|
||||
### Success Exit Code
|
||||
- **0**: All tests passed
|
||||
|
||||
### Error Exit Codes
|
||||
- **Non-zero**: One or more tests failed
|
||||
|
||||
### Console Output
|
||||
Example output:
|
||||
```
|
||||
✓ src/components/Button.test.tsx (3)
|
||||
✓ src/utils/helpers.test.ts (5)
|
||||
✓ src/hooks/useAuth.test.ts (4)
|
||||
|
||||
Test Files 3 passed (3)
|
||||
Tests 12 passed (12)
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Basic Execution
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit
|
||||
```
|
||||
|
||||
### Example 2: Watch Mode for TDD
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit -- --watch
|
||||
```
|
||||
|
||||
### Example 3: Test Specific File
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit -- Button.test.tsx
|
||||
```
|
||||
|
||||
### Example 4: UI Mode (Interactive)
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit -- --ui
|
||||
```
|
||||
|
||||
### Example 5: Reporter Configuration
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh test-frontend-unit -- --reporter=verbose
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Errors
|
||||
|
||||
#### Error: Cannot find module
|
||||
**Solution**: Run `npm install` to ensure all dependencies are installed
|
||||
|
||||
#### Error: Test timeout
|
||||
**Solution**: Increase timeout in vitest.config.ts or fix hanging async tests
|
||||
|
||||
#### Error: Unexpected token
|
||||
**Solution**: Check for syntax errors in test files
|
||||
|
||||
## Related Skills
|
||||
|
||||
- test-frontend-coverage - Run tests with coverage analysis (slower)
|
||||
- test-backend-unit - Backend Go unit tests
|
||||
- build-check-go - Verify builds without running tests
|
||||
|
||||
## Notes
|
||||
|
||||
- **Execution Time**: Fast execution (~3-5 seconds typical)
|
||||
- **No Coverage**: Does not generate coverage reports
|
||||
- **Vitest Features**: Full access to Vitest CLI options via arguments
|
||||
- **Idempotency**: Safe to run multiple times
|
||||
- **Caching**: Benefits from Vitest's smart caching
|
||||
- **Suitable For**: Pre-commit hooks, quick feedback, TDD workflows
|
||||
- **Watch Mode**: Available for interactive development
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project Team
|
||||
**Source**: Inline task command
|
||||
22
.github/skills/utility-bump-beta-scripts/run.sh
vendored
Executable file
22
.github/skills/utility-bump-beta-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Utility: Bump Beta Version - Execution Script
|
||||
# ==============================================================================
|
||||
# This script increments the beta version number across all project files.
|
||||
# It wraps the original bump_beta.sh script.
|
||||
#
|
||||
# Usage: ./run.sh
|
||||
# Exit codes: 0 = success, non-zero = failure
|
||||
# ==============================================================================
|
||||
|
||||
# Determine the repository root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Change to repository root
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Execute the bump beta script
|
||||
exec scripts/bump_beta.sh "$@"
|
||||
201
.github/skills/utility-bump-beta.SKILL.md
vendored
Normal file
201
.github/skills/utility-bump-beta.SKILL.md
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
---
|
||||
name: "utility-bump-beta"
|
||||
version: "1.0.0"
|
||||
description: "Increments beta version number across all project files for pre-release versioning"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "utility"
|
||||
- "versioning"
|
||||
- "release"
|
||||
- "automation"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "git"
|
||||
version: ">=2.0"
|
||||
optional: false
|
||||
- name: "sed"
|
||||
version: ">=4.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters: []
|
||||
outputs:
|
||||
- name: "new_version"
|
||||
type: "string"
|
||||
description: "The new beta version number"
|
||||
path: ".version"
|
||||
metadata:
|
||||
category: "utility"
|
||||
subcategory: "versioning"
|
||||
execution_time: "short"
|
||||
risk_level: "medium"
|
||||
ci_cd_safe: false
|
||||
requires_network: false
|
||||
idempotent: false
|
||||
---
|
||||
|
||||
# Utility: Bump Beta Version
|
||||
|
||||
## Overview
|
||||
|
||||
Automates beta version bumping across all project files. This skill intelligently increments version numbers following semantic versioning conventions for beta releases, updating multiple files in sync to maintain consistency.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Git repository initialized
|
||||
- Write access to project files
|
||||
- Clean working directory (recommended)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
.github/skills/utility-bump-beta-scripts/run.sh
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh utility-bump-beta
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Utility: Bump Beta Version**
|
||||
|
||||
## Parameters
|
||||
|
||||
This skill accepts no parameters. Version bumping logic is automatic based on current version format.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
This skill requires no environment variables.
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0
|
||||
- **Error Exit Codes**: Non-zero on failure
|
||||
- **Modified Files**:
|
||||
- `.version`
|
||||
- `backend/internal/version/version.go`
|
||||
- `frontend/package.json`
|
||||
- `backend/package.json` (if exists)
|
||||
- **Git Tag**: `v{NEW_VERSION}` (if user confirms)
|
||||
|
||||
### Output Example
|
||||
|
||||
```
|
||||
Starting Beta Version Bump...
|
||||
Current Version: 0.3.0-beta.2
|
||||
New Version: 0.3.0-beta.3
|
||||
Updated .version
|
||||
Updated backend/internal/version/version.go
|
||||
Updated frontend/package.json
|
||||
Updated backend/package.json
|
||||
Do you want to commit and tag this version? (y/n) y
|
||||
Committed and tagged v0.3.0-beta.3
|
||||
Remember to push: git push origin feature/beta-release --tags
|
||||
```
|
||||
|
||||
## Version Bumping Logic
|
||||
|
||||
### Current Version is Beta (x.y.z-beta.N)
|
||||
|
||||
Increments the beta number:
|
||||
- `0.3.0-beta.2` → `0.3.0-beta.3`
|
||||
- `1.0.0-beta.5` → `1.0.0-beta.6`
|
||||
|
||||
### Current Version is Plain Semver (x.y.z)
|
||||
|
||||
Bumps minor version and starts beta.1:
|
||||
- `0.3.0` → `0.4.0-beta.1`
|
||||
- `1.2.0` → `1.3.0-beta.1`
|
||||
|
||||
### Current Version is Alpha or Unrecognized
|
||||
|
||||
Defaults to safe fallback:
|
||||
- `0.3.0-alpha` → `0.3.0-beta.1`
|
||||
- `invalid-version` → `0.3.0-beta.1`
|
||||
|
||||
## Files Updated
|
||||
|
||||
1. **`.version`**: Project root version file
|
||||
2. **`backend/internal/version/version.go`**: Go version constant
|
||||
3. **`frontend/package.json`**: Frontend package version
|
||||
4. **`backend/package.json`**: Backend package version (if exists)
|
||||
|
||||
All files are updated with consistent version strings using `sed` regex replacement.
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Bump Beta Before Release
|
||||
|
||||
```bash
|
||||
# Bump version for next beta iteration
|
||||
.github/skills/utility-bump-beta-scripts/run.sh
|
||||
|
||||
# Confirm when prompted to commit and tag
|
||||
# Then push to remote
|
||||
git push origin feature/beta-release --tags
|
||||
```
|
||||
|
||||
### Example 2: Bump Without Committing
|
||||
|
||||
```bash
|
||||
# Make version changes but skip git operations
|
||||
.github/skills/utility-bump-beta-scripts/run.sh
|
||||
# Answer 'n' when prompted about committing
|
||||
```
|
||||
|
||||
## Interactive Confirmation
|
||||
|
||||
After updating files, the script prompts:
|
||||
|
||||
```
|
||||
Do you want to commit and tag this version? (y/n)
|
||||
```
|
||||
|
||||
- **Yes (y)**: Creates git commit and tag automatically
|
||||
- **No (n)**: Leaves changes staged for manual review
|
||||
|
||||
## Error Handling
|
||||
|
||||
- Validates `.version` file exists and is readable
|
||||
- Uses safe defaults for unrecognized version formats
|
||||
- Does not modify VERSION.md guide content (manual update recommended)
|
||||
- Skips `backend/package.json` if file doesn't exist
|
||||
|
||||
## Post-Execution Steps
|
||||
|
||||
After running this skill:
|
||||
|
||||
1. **Review Changes**: `git diff`
|
||||
2. **Run Tests**: Ensure version change doesn't break builds
|
||||
3. **Push Tags**: `git push origin <branch> --tags`
|
||||
4. **Update CHANGELOG.md**: Manually document changes for this version
|
||||
5. **Verify CI/CD**: Check that automated builds use new version
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [utility-version-check](./utility-version-check.SKILL.md) - Validate version matches tags
|
||||
- [build-check-go](../build-check-go.SKILL.md) - Verify build after version bump
|
||||
|
||||
## Notes
|
||||
|
||||
- **Not Idempotent**: Running multiple times increments version each time
|
||||
- **Risk Level: Medium**: Modifies multiple critical files
|
||||
- **Git State**: Recommended to have clean working directory before running
|
||||
- **Manual Review**: Always review version changes before pushing
|
||||
- **VERSION.md**: Update manually as it contains documentation, not just version
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: `scripts/bump_beta.sh`
|
||||
22
.github/skills/utility-clear-go-cache-scripts/run.sh
vendored
Executable file
22
.github/skills/utility-clear-go-cache-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Utility: Clear Go Cache - Execution Script
|
||||
# ==============================================================================
|
||||
# This script clears Go build, test, and module caches, plus gopls cache.
|
||||
# It wraps the original clear-go-cache.sh script.
|
||||
#
|
||||
# Usage: ./run.sh
|
||||
# Exit codes: 0 = success, 1 = failure
|
||||
# ==============================================================================
|
||||
|
||||
# Determine the repository root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Change to repository root
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Execute the cache clear script
|
||||
exec scripts/clear-go-cache.sh "$@"
|
||||
181
.github/skills/utility-clear-go-cache.SKILL.md
vendored
Normal file
181
.github/skills/utility-clear-go-cache.SKILL.md
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
---
|
||||
name: "utility-clear-go-cache"
|
||||
version: "1.0.0"
|
||||
description: "Clears Go build, test, and module caches along with gopls cache for troubleshooting"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "utility"
|
||||
- "golang"
|
||||
- "cache"
|
||||
- "troubleshooting"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "go"
|
||||
version: ">=1.23"
|
||||
optional: false
|
||||
environment_variables:
|
||||
- name: "XDG_CACHE_HOME"
|
||||
description: "XDG cache directory (defaults to $HOME/.cache)"
|
||||
default: "$HOME/.cache"
|
||||
required: false
|
||||
parameters: []
|
||||
outputs:
|
||||
- name: "exit_code"
|
||||
type: "integer"
|
||||
description: "0 on success, 1 on failure"
|
||||
metadata:
|
||||
category: "utility"
|
||||
subcategory: "cache-management"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: false
|
||||
requires_network: true
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Utility: Clear Go Cache
|
||||
|
||||
## Overview
|
||||
|
||||
Clears all Go-related caches including build cache, test cache, module cache, and gopls (Go Language Server) cache. This is useful for troubleshooting build issues, resolving stale dependency problems, or cleaning up disk space.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Go toolchain installed (go 1.23+)
|
||||
- Write access to cache directories
|
||||
- Internet connection (for re-downloading modules)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
.github/skills/utility-clear-go-cache-scripts/run.sh
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh utility-clear-go-cache
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Utility: Clear Go Cache**
|
||||
|
||||
## Parameters
|
||||
|
||||
This skill accepts no parameters.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
| Variable | Required | Default | Description |
|
||||
|----------|----------|---------|-------------|
|
||||
| XDG_CACHE_HOME | No | $HOME/.cache | XDG cache directory location |
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0
|
||||
- **Error Exit Codes**: 1 - Cache clearing failed
|
||||
- **Console Output**: Progress messages and next steps
|
||||
|
||||
### Output Example
|
||||
|
||||
```
|
||||
Clearing Go build and module caches...
|
||||
Clearing gopls cache...
|
||||
Re-downloading modules...
|
||||
Caches cleared and modules re-downloaded.
|
||||
Next steps:
|
||||
- Restart your editor's Go language server (gopls)
|
||||
- In VS Code: Command Palette -> 'Go: Restart Language Server'
|
||||
- Verify the toolchain:
|
||||
$ go version
|
||||
$ gopls version
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Troubleshoot Build Issues
|
||||
|
||||
```bash
|
||||
# Clear caches when experiencing build errors
|
||||
.github/skills/utility-clear-go-cache-scripts/run.sh
|
||||
|
||||
# Restart VS Code's Go language server
|
||||
# Command Palette: "Go: Restart Language Server"
|
||||
```
|
||||
|
||||
### Example 2: Clean Development Environment
|
||||
|
||||
```bash
|
||||
# Clear caches before major Go version upgrade
|
||||
.github/skills/utility-clear-go-cache-scripts/run.sh
|
||||
|
||||
# Verify installation
|
||||
go version
|
||||
gopls version
|
||||
```
|
||||
|
||||
## What Gets Cleared
|
||||
|
||||
This skill clears the following:
|
||||
|
||||
1. **Go Build Cache**: `go clean -cache`
|
||||
- Compiled object files
|
||||
- Build artifacts
|
||||
|
||||
2. **Go Test Cache**: `go clean -testcache`
|
||||
- Cached test results
|
||||
|
||||
3. **Go Module Cache**: `go clean -modcache`
|
||||
- Downloaded module sources
|
||||
- Module checksums
|
||||
|
||||
4. **gopls Cache**: Removes `$XDG_CACHE_HOME/gopls` or `$HOME/.cache/gopls`
|
||||
- Language server indexes
|
||||
- Cached analysis results
|
||||
|
||||
5. **Re-downloads**: `go mod download`
|
||||
- Fetches all dependencies fresh
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when experiencing:
|
||||
- Build failures after dependency updates
|
||||
- gopls crashes or incorrect diagnostics
|
||||
- Module checksum mismatches
|
||||
- Stale test cache results
|
||||
- Disk space issues related to Go caches
|
||||
- IDE reporting incorrect errors
|
||||
|
||||
## Error Handling
|
||||
|
||||
- All cache clearing operations use `|| true` to continue even if a cache doesn't exist
|
||||
- Module re-download requires network access
|
||||
- Exits with error if `backend/` directory not found
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [build-check-go](../build-check-go.SKILL.md) - Verify Go build after cache clear
|
||||
- [test-backend-unit](./test-backend-unit.SKILL.md) - Run tests after cache clear
|
||||
|
||||
## Notes
|
||||
|
||||
- **Warning**: This operation re-downloads all Go modules (may be slow on poor network)
|
||||
- Not CI/CD safe due to network dependency and destructive nature
|
||||
- Requires manual IDE restart after execution
|
||||
- Safe to run multiple times (idempotent)
|
||||
- Consider using this before major Go version upgrades
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: `scripts/clear-go-cache.sh`
|
||||
22
.github/skills/utility-db-recovery-scripts/run.sh
vendored
Executable file
22
.github/skills/utility-db-recovery-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Utility: Database Recovery - Execution Script
|
||||
# ==============================================================================
|
||||
# This script performs SQLite database integrity checks and recovery.
|
||||
# It wraps the original db-recovery.sh script.
|
||||
#
|
||||
# Usage: ./run.sh [--force]
|
||||
# Exit codes: 0 = success, 1 = failure
|
||||
# ==============================================================================
|
||||
|
||||
# Determine the repository root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Change to repository root
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Execute the database recovery script
|
||||
exec scripts/db-recovery.sh "$@"
|
||||
299
.github/skills/utility-db-recovery.SKILL.md
vendored
Normal file
299
.github/skills/utility-db-recovery.SKILL.md
vendored
Normal file
@@ -0,0 +1,299 @@
|
||||
---
|
||||
name: "utility-db-recovery"
|
||||
version: "1.0.0"
|
||||
description: "Performs SQLite database integrity checks and recovery operations for Charon database"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "utility"
|
||||
- "database"
|
||||
- "recovery"
|
||||
- "sqlite"
|
||||
- "backup"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "sqlite3"
|
||||
version: ">=3.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters:
|
||||
- name: "--force"
|
||||
type: "flag"
|
||||
description: "Skip confirmation prompts"
|
||||
default: "false"
|
||||
required: false
|
||||
outputs:
|
||||
- name: "exit_code"
|
||||
type: "integer"
|
||||
description: "0 on success, 1 on failure"
|
||||
- name: "backup_file"
|
||||
type: "file"
|
||||
description: "Timestamped backup of database"
|
||||
path: "backend/data/backups/charon_backup_*.db"
|
||||
metadata:
|
||||
category: "utility"
|
||||
subcategory: "database"
|
||||
execution_time: "medium"
|
||||
risk_level: "high"
|
||||
ci_cd_safe: false
|
||||
requires_network: false
|
||||
idempotent: false
|
||||
---
|
||||
|
||||
# Utility: Database Recovery
|
||||
|
||||
## Overview
|
||||
|
||||
Performs comprehensive SQLite database integrity checks and recovery operations for the Charon database. This skill can detect corruption, create backups, and attempt automatic recovery using SQLite's `.dump` and rebuild strategy. Critical for maintaining database health and recovering from corruption.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- `sqlite3` command-line tool installed
|
||||
- Database file exists at expected location
|
||||
- Write permissions for backup directory
|
||||
- Sufficient disk space for backups and recovery
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage (Interactive)
|
||||
|
||||
```bash
|
||||
.github/skills/utility-db-recovery-scripts/run.sh
|
||||
```
|
||||
|
||||
### Force Mode (Non-Interactive)
|
||||
|
||||
```bash
|
||||
.github/skills/utility-db-recovery-scripts/run.sh --force
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh utility-db-recovery [--force]
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Utility: Database Recovery**
|
||||
|
||||
## Parameters
|
||||
|
||||
| Parameter | Type | Required | Default | Description |
|
||||
|-----------|------|----------|---------|-------------|
|
||||
| --force | flag | No | false | Skip confirmation prompts |
|
||||
| -f | flag | No | false | Alias for --force |
|
||||
|
||||
## Environment Variables
|
||||
|
||||
This skill requires no environment variables. It auto-detects Docker vs local environment.
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 - Database healthy or recovered
|
||||
- **Error Exit Codes**: 1 - Recovery failed or prerequisites missing
|
||||
- **Backup Files**: `backend/data/backups/charon_backup_YYYYMMDD_HHMMSS.db`
|
||||
- **Dump Files**: `backend/data/backups/charon_dump_YYYYMMDD_HHMMSS.sql` (if recovery attempted)
|
||||
- **Recovered DB**: `backend/data/backups/charon_recovered_YYYYMMDD_HHMMSS.db` (temporary)
|
||||
|
||||
### Success Output Example (Healthy Database)
|
||||
|
||||
```
|
||||
==============================================
|
||||
Charon Database Recovery Tool
|
||||
==============================================
|
||||
|
||||
[INFO] sqlite3 found: 3.40.1
|
||||
[INFO] Running in local development environment
|
||||
[INFO] Database path: backend/data/charon.db
|
||||
[INFO] Created backup directory: backend/data/backups
|
||||
[INFO] Creating backup: backend/data/backups/charon_backup_20251220_143022.db
|
||||
[SUCCESS] Backup created successfully
|
||||
|
||||
==============================================
|
||||
Integrity Check Results
|
||||
==============================================
|
||||
[INFO] Running SQLite integrity check...
|
||||
ok
|
||||
[SUCCESS] Database integrity check passed!
|
||||
[INFO] WAL mode already enabled
|
||||
[INFO] Cleaning up old backups (keeping last 10)...
|
||||
|
||||
==============================================
|
||||
Summary
|
||||
==============================================
|
||||
[SUCCESS] Database is healthy
|
||||
[INFO] Backup stored at: backend/data/backups/charon_backup_20251220_143022.db
|
||||
```
|
||||
|
||||
### Recovery Output Example (Corrupted Database)
|
||||
|
||||
```
|
||||
==============================================
|
||||
Integrity Check Results
|
||||
==============================================
|
||||
[INFO] Running SQLite integrity check...
|
||||
*** in database main ***
|
||||
Page 15: btreeInitPage() returns error code 11
|
||||
[ERROR] Database integrity check FAILED
|
||||
|
||||
WARNING: Database corruption detected!
|
||||
This script will attempt to recover the database.
|
||||
A backup has already been created at: backend/data/backups/charon_backup_20251220_143022.db
|
||||
|
||||
Continue with recovery? (y/N): y
|
||||
|
||||
==============================================
|
||||
Recovery Process
|
||||
==============================================
|
||||
[INFO] Attempting database recovery...
|
||||
[INFO] Exporting database via .dump command...
|
||||
[SUCCESS] Database dump created: backend/data/backups/charon_dump_20251220_143022.sql
|
||||
[INFO] Creating new database from dump...
|
||||
[SUCCESS] Recovered database created: backend/data/backups/charon_recovered_20251220_143022.db
|
||||
[INFO] Verifying recovered database integrity...
|
||||
[SUCCESS] Recovered database passed integrity check
|
||||
[INFO] Replacing original database with recovered version...
|
||||
[SUCCESS] Database replaced successfully
|
||||
[INFO] Enabling WAL (Write-Ahead Logging) mode...
|
||||
[SUCCESS] WAL mode enabled
|
||||
|
||||
==============================================
|
||||
Summary
|
||||
==============================================
|
||||
[SUCCESS] Database recovery completed successfully!
|
||||
[INFO] Original backup: backend/data/backups/charon_backup_20251220_143022.db
|
||||
[INFO] Please restart the Charon application
|
||||
```
|
||||
|
||||
## Environment Detection
|
||||
|
||||
The skill automatically detects whether it's running in:
|
||||
|
||||
1. **Docker Environment**: Database at `/app/data/charon.db`
|
||||
2. **Local Development**: Database at `backend/data/charon.db`
|
||||
|
||||
Backup locations adjust accordingly.
|
||||
|
||||
## Recovery Process
|
||||
|
||||
When corruption is detected, the recovery process:
|
||||
|
||||
1. **Creates Backup**: Timestamped copy of current database (including WAL/SHM)
|
||||
2. **Exports Data**: Uses `.dump` command to export SQL (works with partial corruption)
|
||||
3. **Creates New DB**: Builds fresh database from dump
|
||||
4. **Verifies Integrity**: Runs integrity check on recovered database
|
||||
5. **Replaces Original**: Moves recovered database to original location
|
||||
6. **Enables WAL Mode**: Configures Write-Ahead Logging for durability
|
||||
7. **Cleanup**: Removes old backups (keeps last 10)
|
||||
|
||||
## When to Use This Skill
|
||||
|
||||
Use this skill when:
|
||||
- Application fails to start with database errors
|
||||
- SQLite reports "database disk image is malformed"
|
||||
- Random crashes or data inconsistencies
|
||||
- After unclean shutdown (power loss, kill -9)
|
||||
- Before major database migrations
|
||||
- As part of regular maintenance schedule
|
||||
|
||||
## Backup Management
|
||||
|
||||
- **Automatic Backups**: Created before any recovery operation
|
||||
- **Retention**: Keeps last 10 backups automatically
|
||||
- **Includes WAL/SHM**: Backs up Write-Ahead Log files if present
|
||||
- **Timestamped**: Format `charon_backup_YYYYMMDD_HHMMSS.db`
|
||||
|
||||
## WAL Mode
|
||||
|
||||
The skill ensures Write-Ahead Logging (WAL) is enabled:
|
||||
- **Benefits**: Better concurrency, atomic commits, crash resistance
|
||||
- **Trade-offs**: Multiple files (db, wal, shm) instead of single file
|
||||
- **Recommended**: For all production deployments
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Regular Health Check
|
||||
|
||||
```bash
|
||||
# Run integrity check (creates backup even if healthy)
|
||||
.github/skills/utility-db-recovery-scripts/run.sh
|
||||
```
|
||||
|
||||
### Example 2: Force Recovery Without Prompts
|
||||
|
||||
```bash
|
||||
# Useful for automation/scripts
|
||||
.github/skills/utility-db-recovery-scripts/run.sh --force
|
||||
```
|
||||
|
||||
### Example 3: Docker Container Recovery
|
||||
|
||||
```bash
|
||||
# Run inside Docker container
|
||||
docker exec -it charon-app bash
|
||||
/app/.github/skills/utility-db-recovery-scripts/run.sh --force
|
||||
```
|
||||
|
||||
## Error Handling
|
||||
|
||||
- **No sqlite3**: Exits with installation instructions
|
||||
- **Database not found**: Exits with clear error message
|
||||
- **Dump fails**: Recovery aborted, backup preserved
|
||||
- **Recovered DB fails integrity**: Original backup preserved
|
||||
- **Insufficient disk space**: Operations fail safely
|
||||
|
||||
## Post-Recovery Steps
|
||||
|
||||
After successful recovery:
|
||||
|
||||
1. **Restart Application**: `docker compose restart` or restart process
|
||||
2. **Verify Functionality**: Test critical features
|
||||
3. **Monitor Logs**: Watch for any residual issues
|
||||
4. **Review Backup**: Keep the backup until stability confirmed
|
||||
5. **Investigate Root Cause**: Determine what caused corruption
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [docker-start-dev](./docker-start-dev.SKILL.md) - Restart containers after recovery
|
||||
- [docker-stop-dev](./docker-stop-dev.SKILL.md) - Stop containers before recovery
|
||||
|
||||
## Notes
|
||||
|
||||
- **High Risk**: Destructive operation, always creates backup first
|
||||
- **Not CI/CD Safe**: Requires user interaction (unless --force)
|
||||
- **Not Idempotent**: Each run creates new backup
|
||||
- **Manual Intervention**: Some corruption may require manual SQL fixes
|
||||
- **WAL Files**: Don't delete WAL/SHM files manually during operation
|
||||
- **Backup Location**: Ensure backups are stored on different disk from database
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Recovery Fails with Empty Dump
|
||||
|
||||
- Database may be too corrupted
|
||||
- Try `.recover` command (SQLite 3.29+)
|
||||
- Restore from external backup
|
||||
|
||||
### "Database is Locked" Error
|
||||
|
||||
- Stop application first
|
||||
- Check for other processes accessing database
|
||||
- Use `fuser backend/data/charon.db` to find processes
|
||||
|
||||
### Recovery Succeeds but Data Missing
|
||||
|
||||
- Some corruption may result in data loss
|
||||
- Review backup before deleting
|
||||
- Check dump SQL file for missing tables
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: `scripts/db-recovery.sh`
|
||||
22
.github/skills/utility-version-check-scripts/run.sh
vendored
Executable file
22
.github/skills/utility-version-check-scripts/run.sh
vendored
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# ==============================================================================
|
||||
# Utility: Version Check - Execution Script
|
||||
# ==============================================================================
|
||||
# This script validates that the .version file matches the latest git tag.
|
||||
# It wraps the original check-version-match-tag.sh script.
|
||||
#
|
||||
# Usage: ./run.sh
|
||||
# Exit codes: 0 = success, 1 = version mismatch
|
||||
# ==============================================================================
|
||||
|
||||
# Determine the repository root directory
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
REPO_ROOT="$(cd "$SCRIPT_DIR/../../.." && pwd)"
|
||||
|
||||
# Change to repository root
|
||||
cd "$REPO_ROOT"
|
||||
|
||||
# Execute the version check script
|
||||
exec scripts/check-version-match-tag.sh "$@"
|
||||
142
.github/skills/utility-version-check.SKILL.md
vendored
Normal file
142
.github/skills/utility-version-check.SKILL.md
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
---
|
||||
name: "utility-version-check"
|
||||
version: "1.0.0"
|
||||
description: "Validates that VERSION.md/version file matches the latest git tag for release consistency"
|
||||
author: "Charon Project"
|
||||
license: "MIT"
|
||||
tags:
|
||||
- "utility"
|
||||
- "versioning"
|
||||
- "validation"
|
||||
- "git"
|
||||
compatibility:
|
||||
os:
|
||||
- "linux"
|
||||
- "darwin"
|
||||
shells:
|
||||
- "bash"
|
||||
requirements:
|
||||
- name: "git"
|
||||
version: ">=2.0"
|
||||
optional: false
|
||||
environment_variables: []
|
||||
parameters: []
|
||||
outputs:
|
||||
- name: "exit_code"
|
||||
type: "integer"
|
||||
description: "0 if version matches, 1 if mismatch or error"
|
||||
metadata:
|
||||
category: "utility"
|
||||
subcategory: "versioning"
|
||||
execution_time: "short"
|
||||
risk_level: "low"
|
||||
ci_cd_safe: true
|
||||
requires_network: false
|
||||
idempotent: true
|
||||
---
|
||||
|
||||
# Utility: Version Check
|
||||
|
||||
## Overview
|
||||
|
||||
Validates that the version specified in `.version` file matches the latest git tag. This ensures version consistency across the codebase and prevents version drift during releases. The check is used in CI/CD to enforce version tagging discipline.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
- Git repository with tags
|
||||
- `.version` file in repository root (optional)
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Usage
|
||||
|
||||
```bash
|
||||
.github/skills/utility-version-check-scripts/run.sh
|
||||
```
|
||||
|
||||
### Via Skill Runner
|
||||
|
||||
```bash
|
||||
.github/skills/scripts/skill-runner.sh utility-version-check
|
||||
```
|
||||
|
||||
### Via VS Code Task
|
||||
|
||||
Use the task: **Utility: Check Version Match Tag**
|
||||
|
||||
## Parameters
|
||||
|
||||
This skill accepts no parameters.
|
||||
|
||||
## Environment Variables
|
||||
|
||||
This skill requires no environment variables.
|
||||
|
||||
## Outputs
|
||||
|
||||
- **Success Exit Code**: 0 - Version matches latest tag or no tags exist
|
||||
- **Error Exit Codes**: 1 - Version mismatch detected
|
||||
- **Console Output**: Validation result message
|
||||
|
||||
### Success Output Example
|
||||
|
||||
```
|
||||
OK: .version matches latest Git tag v0.3.0-beta.2
|
||||
```
|
||||
|
||||
### Error Output Example
|
||||
|
||||
```
|
||||
ERROR: .version (0.3.0-beta.3) does not match latest Git tag (v0.3.0-beta.2)
|
||||
To sync, either update .version or tag with 'v0.3.0-beta.3'
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Example 1: Check Version During Release
|
||||
|
||||
```bash
|
||||
# Before tagging a new release
|
||||
.github/skills/utility-version-check-scripts/run.sh
|
||||
```
|
||||
|
||||
### Example 2: CI/CD Integration
|
||||
|
||||
```yaml
|
||||
- name: Validate Version
|
||||
run: .github/skills/scripts/skill-runner.sh utility-version-check
|
||||
```
|
||||
|
||||
## Version Normalization
|
||||
|
||||
The skill normalizes both the `.version` file content and git tag by:
|
||||
- Stripping leading `v` prefix (e.g., `v1.0.0` → `1.0.0`)
|
||||
- Removing newline and carriage return characters
|
||||
- Comparing normalized versions
|
||||
|
||||
This allows flexibility in tagging conventions while ensuring consistency.
|
||||
|
||||
## Error Handling
|
||||
|
||||
- **No .version file**: Exits with 0 (skip check)
|
||||
- **No git tags**: Exits with 0 (skip check, allows commits before first tag)
|
||||
- **Version mismatch**: Exits with 1 and provides guidance
|
||||
- **Git errors**: Script fails with appropriate error message
|
||||
|
||||
## Related Skills
|
||||
|
||||
- [utility-bump-beta](./utility-bump-beta.SKILL.md) - Increment beta version
|
||||
- [build-check-go](../build-check-go.SKILL.md) - Verify Go build integrity
|
||||
|
||||
## Notes
|
||||
|
||||
- This check is **non-blocking** when no tags exist (allows initial development)
|
||||
- Version format is flexible (supports semver, beta, alpha suffixes)
|
||||
- Used in CI/CD to prevent merging PRs with version mismatches
|
||||
- Part of the release automation workflow
|
||||
|
||||
---
|
||||
|
||||
**Last Updated**: 2025-12-20
|
||||
**Maintained by**: Charon Project
|
||||
**Source**: `scripts/check-version-match-tag.sh`
|
||||
4
.github/workflows/auto-add-to-project.yml
vendored
4
.github/workflows/auto-add-to-project.yml
vendored
@@ -6,6 +6,10 @@ on:
|
||||
pull_request:
|
||||
types: [opened, reopened]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.issue.number || github.event.pull_request.number }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
add-to-project:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/auto-changelog.yml
vendored
4
.github/workflows/auto-changelog.yml
vendored
@@ -6,6 +6,10 @@ on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
update-draft:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/auto-label-issues.yml
vendored
4
.github/workflows/auto-label-issues.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
issues:
|
||||
types: [opened, edited]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.issue.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
auto-label:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/auto-versioning.yml
vendored
4
.github/workflows/auto-versioning.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
push:
|
||||
branches: [ main ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
12
.github/workflows/benchmark.yml
vendored
12
.github/workflows/benchmark.yml
vendored
@@ -15,6 +15,13 @@ on:
|
||||
- 'backend/**'
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.25.5'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
deployments: write
|
||||
@@ -29,7 +36,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: backend/go.sum
|
||||
|
||||
- name: Run Benchmark
|
||||
@@ -40,7 +47,8 @@ jobs:
|
||||
# Only store results on pushes to main - PRs just run benchmarks without storage
|
||||
# This avoids gh-pages branch errors and permission issues on fork PRs
|
||||
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
||||
uses: benchmark-action/github-action-benchmark@v1
|
||||
# Security: Pinned to full SHA for supply chain security
|
||||
uses: benchmark-action/github-action-benchmark@4e0b38bc48375986542b13c0d8976b7b80c60c00 # v1
|
||||
with:
|
||||
name: Go Benchmark
|
||||
tool: 'go'
|
||||
|
||||
4
.github/workflows/caddy-major-monitor.yml
vendored
4
.github/workflows/caddy-major-monitor.yml
vendored
@@ -5,6 +5,10 @@ on:
|
||||
- cron: '17 7 * * 1' # Mondays at 07:17 UTC
|
||||
workflow_dispatch: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
|
||||
12
.github/workflows/codecov-upload.yml
vendored
12
.github/workflows/codecov-upload.yml
vendored
@@ -7,6 +7,14 @@ on:
|
||||
- development
|
||||
- 'feature/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.25.5'
|
||||
NODE_VERSION: '24.12.0'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
@@ -23,7 +31,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: backend/go.sum
|
||||
|
||||
- name: Run Go tests with coverage
|
||||
@@ -54,7 +62,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
with:
|
||||
node-version: '24.12.0'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
|
||||
15
.github/workflows/codeql.yml
vendored
15
.github/workflows/codeql.yml
vendored
@@ -8,6 +8,13 @@ on:
|
||||
schedule:
|
||||
- cron: '0 3 * * 1'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.25.5'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
security-events: write
|
||||
@@ -34,7 +41,7 @@ jobs:
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4
|
||||
uses: github/codeql-action/init@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
@@ -42,12 +49,12 @@ jobs:
|
||||
if: matrix.language == 'go'
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4
|
||||
uses: github/codeql-action/autobuild@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4
|
||||
uses: github/codeql-action/analyze@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4
|
||||
with:
|
||||
category: "/language:${{ matrix.language }}"
|
||||
|
||||
4
.github/workflows/create-labels.yml
vendored
4
.github/workflows/create-labels.yml
vendored
@@ -4,6 +4,10 @@ name: Create Project Labels
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
create-labels:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
112
.github/workflows/docker-build.yml
vendored
112
.github/workflows/docker-build.yml
vendored
@@ -15,6 +15,10 @@ on:
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/charon
|
||||
@@ -27,6 +31,8 @@ jobs:
|
||||
contents: read
|
||||
packages: write
|
||||
security-events: write
|
||||
id-token: write # Required for SBOM attestation
|
||||
attestations: write # Required for SBOM attestation
|
||||
|
||||
outputs:
|
||||
skip_build: ${{ steps.skip.outputs.skip_build }}
|
||||
@@ -71,7 +77,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
- name: Set up Docker Buildx
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
- name: Resolve Caddy base digest
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
id: caddy
|
||||
@@ -98,7 +104,7 @@ jobs:
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/development' }}
|
||||
type=raw,value=beta,enable=${{ github.ref == 'refs/heads/feature/beta-release' }}
|
||||
type=raw,value=pr-${{ github.ref_name }},enable=${{ github.event_name == 'pull_request' }}
|
||||
type=raw,value=pr-${{ github.event.pull_request.number }},enable=${{ github.event_name == 'pull_request' }}
|
||||
type=sha,format=short,enable=${{ github.event_name != 'pull_request' }}
|
||||
- name: Build and push Docker image
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
@@ -108,6 +114,7 @@ jobs:
|
||||
context: .
|
||||
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
load: ${{ github.event_name == 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
pull: true # Always pull fresh base images to get latest security patches
|
||||
@@ -119,6 +126,75 @@ jobs:
|
||||
VCS_REF=${{ github.sha }}
|
||||
CADDY_IMAGE=${{ steps.caddy.outputs.image }}
|
||||
|
||||
- name: Verify Caddy Security Patches (CVE-2025-68156)
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
timeout-minutes: 2
|
||||
run: |
|
||||
echo "🔍 Verifying Caddy binary contains patched expr-lang/expr@v1.17.7..."
|
||||
echo ""
|
||||
|
||||
# Determine the image reference based on event type
|
||||
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
||||
IMAGE_REF="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:pr-${{ github.event.pull_request.number }}"
|
||||
echo "Using PR image: $IMAGE_REF"
|
||||
else
|
||||
IMAGE_REF="${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}"
|
||||
echo "Using digest: $IMAGE_REF"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "==> Caddy version:"
|
||||
timeout 30s docker run --rm $IMAGE_REF caddy version || echo "⚠️ Caddy version check timed out or failed"
|
||||
|
||||
echo ""
|
||||
echo "==> Extracting Caddy binary for inspection..."
|
||||
CONTAINER_ID=$(docker create $IMAGE_REF)
|
||||
docker cp ${CONTAINER_ID}:/usr/bin/caddy ./caddy_binary
|
||||
docker rm ${CONTAINER_ID}
|
||||
|
||||
echo ""
|
||||
echo "==> Checking if Go toolchain is available locally..."
|
||||
if command -v go >/dev/null 2>&1; then
|
||||
echo "✅ Go found locally, inspecting binary dependencies..."
|
||||
go version -m ./caddy_binary > caddy_deps.txt
|
||||
|
||||
echo ""
|
||||
echo "==> Searching for expr-lang/expr dependency:"
|
||||
if grep -i "expr-lang/expr" caddy_deps.txt; then
|
||||
EXPR_VERSION=$(grep "expr-lang/expr" caddy_deps.txt | awk '{print $3}')
|
||||
echo ""
|
||||
echo "✅ Found expr-lang/expr: $EXPR_VERSION"
|
||||
|
||||
# Check if version is v1.17.7 or higher (vulnerable version is v1.16.9)
|
||||
if echo "$EXPR_VERSION" | grep -E "^v1\.(1[7-9]|[2-9][0-9])\.[0-9]+$" >/dev/null; then
|
||||
echo "✅ PASS: expr-lang version $EXPR_VERSION is patched (>= v1.17.7)"
|
||||
else
|
||||
echo "⚠️ WARNING: expr-lang version $EXPR_VERSION may be vulnerable (< v1.17.7)"
|
||||
echo "Expected: v1.17.7 or higher to mitigate CVE-2025-68156"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
echo "⚠️ expr-lang/expr not found in binary dependencies"
|
||||
echo "This could mean:"
|
||||
echo " 1. The dependency was stripped/optimized out"
|
||||
echo " 2. Caddy was built without the expression evaluator"
|
||||
echo " 3. Binary inspection failed"
|
||||
echo ""
|
||||
echo "Displaying all dependencies for review:"
|
||||
cat caddy_deps.txt
|
||||
fi
|
||||
else
|
||||
echo "⚠️ Go toolchain not available in CI environment"
|
||||
echo "Cannot inspect binary modules - skipping dependency verification"
|
||||
echo "Note: Runtime image does not require Go as Caddy is a standalone binary"
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -f ./caddy_binary caddy_deps.txt
|
||||
|
||||
echo ""
|
||||
echo "==> Verification complete"
|
||||
|
||||
- name: Run Trivy scan (table output)
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
|
||||
@@ -152,11 +228,30 @@ jobs:
|
||||
|
||||
- name: Upload Trivy results
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.trivy-check.outputs.exists == 'true'
|
||||
uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
|
||||
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
# Generate SBOM (Software Bill of Materials) for supply chain security
|
||||
- name: Generate SBOM
|
||||
uses: anchore/sbom-action@61119d458adab75f756bc0b9e4bde25725f86a7a # v0.17.2
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
|
||||
format: cyclonedx-json
|
||||
output-file: sbom.cyclonedx.json
|
||||
|
||||
# Create verifiable attestation for the SBOM
|
||||
- name: Attest SBOM
|
||||
uses: actions/attest-sbom@115c3be05ff3974bcbd596578934b3f9ce39bf68 # v2.2.0
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
with:
|
||||
subject-name: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
subject-digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
sbom-path: sbom.cyclonedx.json
|
||||
push-to-registry: true
|
||||
|
||||
- name: Create summary
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
run: |
|
||||
@@ -217,6 +312,7 @@ jobs:
|
||||
traefik/whoami
|
||||
|
||||
- name: Run Charon Container
|
||||
timeout-minutes: 3
|
||||
run: |
|
||||
docker run -d \
|
||||
--name test-container \
|
||||
@@ -224,7 +320,17 @@ jobs:
|
||||
-p 8080:8080 \
|
||||
-p 80:80 \
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
|
||||
|
||||
# Wait for container to be healthy (max 2 minutes)
|
||||
echo "Waiting for container to start..."
|
||||
timeout 120s bash -c 'until docker exec test-container wget -q -O- http://localhost:8080/api/v1/health 2>/dev/null | grep -q "status"; do echo "Waiting..."; sleep 2; done' || {
|
||||
echo "❌ Container failed to become healthy"
|
||||
docker logs test-container
|
||||
exit 1
|
||||
}
|
||||
echo "✅ Container is healthy"
|
||||
- name: Run Integration Test
|
||||
timeout-minutes: 5
|
||||
run: ./scripts/integration-test.sh
|
||||
|
||||
- name: Check container logs
|
||||
|
||||
4
.github/workflows/docker-lint.yml
vendored
4
.github/workflows/docker-lint.yml
vendored
@@ -10,6 +10,10 @@ on:
|
||||
paths:
|
||||
- 'Dockerfile'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
hadolint:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
278
.github/workflows/docker-publish.yml
vendored
278
.github/workflows/docker-publish.yml
vendored
@@ -1,278 +0,0 @@
|
||||
name: Docker Build, Publish & Test
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- development
|
||||
- feature/beta-release
|
||||
# Note: Tags are handled by release-goreleaser.yml to avoid duplicate builds
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- development
|
||||
- feature/beta-release
|
||||
workflow_dispatch:
|
||||
workflow_call:
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/charon
|
||||
|
||||
jobs:
|
||||
build-and-push:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 30
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
security-events: write
|
||||
|
||||
outputs:
|
||||
skip_build: ${{ steps.skip.outputs.skip_build }}
|
||||
digest: ${{ steps.build-and-push.outputs.digest }}
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Normalize image name
|
||||
run: |
|
||||
echo "IMAGE_NAME=$(echo "${{ env.IMAGE_NAME }}" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
|
||||
- name: Determine skip condition
|
||||
id: skip
|
||||
env:
|
||||
ACTOR: ${{ github.actor }}
|
||||
EVENT: ${{ github.event_name }}
|
||||
HEAD_MSG: ${{ github.event.head_commit.message }}
|
||||
REF: ${{ github.ref }}
|
||||
run: |
|
||||
should_skip=false
|
||||
pr_title=""
|
||||
if [ "$EVENT" = "pull_request" ]; then
|
||||
pr_title=$(jq -r '.pull_request.title' "$GITHUB_EVENT_PATH" 2>/dev/null || echo '')
|
||||
fi
|
||||
if [ "$ACTOR" = "renovate[bot]" ]; then should_skip=true; fi
|
||||
if echo "$HEAD_MSG" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi
|
||||
if echo "$HEAD_MSG" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi
|
||||
if echo "$pr_title" | grep -Ei '^chore\(deps' >/dev/null 2>&1; then should_skip=true; fi
|
||||
if echo "$pr_title" | grep -Ei '^chore:' >/dev/null 2>&1; then should_skip=true; fi
|
||||
|
||||
# Always build on beta-release branch to ensure artifacts for testing
|
||||
if [[ "$REF" == "refs/heads/feature/beta-release" ]]; then
|
||||
should_skip=false
|
||||
echo "Force building on beta-release branch"
|
||||
fi
|
||||
|
||||
echo "skip_build=$should_skip" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set up QEMU
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
|
||||
- name: Resolve Caddy base digest
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
id: caddy
|
||||
run: |
|
||||
docker pull caddy:2-alpine
|
||||
DIGEST=$(docker inspect --format='{{index .RepoDigests 0}}' caddy:2-alpine)
|
||||
echo "image=$DIGEST" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Log in to Container Registry
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Extract metadata (tags, labels)
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
id: meta
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5.10.0
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
tags: |
|
||||
type=raw,value=latest,enable={{is_default_branch}}
|
||||
type=raw,value=dev,enable=${{ github.ref == 'refs/heads/development' }}
|
||||
type=raw,value=beta,enable=${{ github.ref == 'refs/heads/feature/beta-release' }}
|
||||
type=raw,value=pr-${{ github.ref_name }},enable=${{ github.event_name == 'pull_request' }}
|
||||
type=sha,format=short,enable=${{ github.event_name != 'pull_request' }}
|
||||
|
||||
- name: Build and push Docker image
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
id: build-and-push
|
||||
uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6
|
||||
with:
|
||||
context: .
|
||||
platforms: ${{ github.event_name == 'pull_request' && 'linux/amd64' || 'linux/amd64,linux/arm64' }}
|
||||
push: ${{ github.event_name != 'pull_request' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
# Always pull fresh base images to get latest security patches
|
||||
pull: true
|
||||
cache-from: type=gha
|
||||
cache-to: type=gha,mode=max
|
||||
build-args: |
|
||||
VERSION=${{ steps.meta.outputs.version }}
|
||||
BUILD_DATE=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
|
||||
VCS_REF=${{ github.sha }}
|
||||
CADDY_IMAGE=${{ steps.caddy.outputs.image }}
|
||||
|
||||
- name: Run Trivy scan (table output)
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
|
||||
format: 'table'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
exit-code: '0'
|
||||
continue-on-error: true
|
||||
|
||||
- name: Run Trivy vulnerability scanner (SARIF)
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
id: trivy
|
||||
uses: aquasecurity/trivy-action@b6643a29fecd7f34b3597bc6acb0a98b03d33ff8 # 0.33.1
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build-and-push.outputs.digest }}
|
||||
format: 'sarif'
|
||||
output: 'trivy-results.sarif'
|
||||
severity: 'CRITICAL,HIGH'
|
||||
continue-on-error: true
|
||||
|
||||
- name: Check Trivy SARIF exists
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true'
|
||||
id: trivy-check
|
||||
run: |
|
||||
if [ -f trivy-results.sarif ]; then
|
||||
echo "exists=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "exists=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Upload Trivy results
|
||||
if: github.event_name != 'pull_request' && steps.skip.outputs.skip_build != 'true' && steps.trivy-check.outputs.exists == 'true'
|
||||
uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
|
||||
with:
|
||||
sarif_file: 'trivy-results.sarif'
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Create summary
|
||||
if: steps.skip.outputs.skip_build != 'true'
|
||||
run: |
|
||||
echo "## 🎉 Docker Image Built Successfully!" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "### 📦 Image Details" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Registry**: GitHub Container Registry (ghcr.io)" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Repository**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Tags**: " >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
echo "${{ steps.meta.outputs.tags }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
test-image:
|
||||
name: Test Docker Image
|
||||
needs: build-and-push
|
||||
runs-on: ubuntu-latest
|
||||
if: needs.build-and-push.outputs.skip_build != 'true' && github.event_name != 'pull_request'
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Normalize image name
|
||||
run: |
|
||||
raw="${{ github.repository_owner }}/${{ github.event.repository.name }}"
|
||||
echo "IMAGE_NAME=$(echo "$raw" | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV
|
||||
|
||||
- name: Determine image tag
|
||||
id: tag
|
||||
run: |
|
||||
if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then
|
||||
echo "tag=latest" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.ref }}" == "refs/heads/development" ]]; then
|
||||
echo "tag=dev" >> $GITHUB_OUTPUT
|
||||
elif [[ "${{ github.ref }}" == refs/tags/v* ]]; then
|
||||
echo "tag=${GITHUB_REF#refs/tags/v}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "tag=sha-$(echo ${{ github.sha }} | cut -c1-7)" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Log in to GitHub Container Registry
|
||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Pull Docker image
|
||||
run: docker pull ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
|
||||
|
||||
- name: Create Docker Network
|
||||
run: docker network create charon-test-net
|
||||
|
||||
- name: Run Upstream Service (whoami)
|
||||
run: |
|
||||
docker run -d \
|
||||
--name whoami \
|
||||
--network charon-test-net \
|
||||
traefik/whoami
|
||||
|
||||
- name: Run Charon Container
|
||||
run: |
|
||||
docker run -d \
|
||||
--name test-container \
|
||||
--network charon-test-net \
|
||||
-p 8080:8080 \
|
||||
-p 80:80 \
|
||||
${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}
|
||||
|
||||
- name: Run Integration Test
|
||||
run: ./scripts/integration-test.sh
|
||||
|
||||
- name: Check container logs
|
||||
if: always()
|
||||
run: docker logs test-container
|
||||
|
||||
- name: Stop container
|
||||
if: always()
|
||||
run: |
|
||||
docker stop test-container whoami || true
|
||||
docker rm test-container whoami || true
|
||||
docker network rm charon-test-net || true
|
||||
|
||||
- name: Create test summary
|
||||
if: always()
|
||||
run: |
|
||||
echo "## 🧪 Docker Image Test Results" >> $GITHUB_STEP_SUMMARY
|
||||
echo "" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Image**: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ steps.tag.outputs.tag }}" >> $GITHUB_STEP_SUMMARY
|
||||
echo "- **Integration Test**: ${{ job.status == 'success' && '✅ Passed' || '❌ Failed' }}" >> $GITHUB_STEP_SUMMARY
|
||||
|
||||
trivy-pr-app-only:
|
||||
name: Trivy (PR) - App-only
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event_name == 'pull_request'
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Build image locally for PR
|
||||
run: |
|
||||
docker build -t charon:pr-${{ github.sha }} .
|
||||
|
||||
- name: Extract `charon` binary from image
|
||||
run: |
|
||||
CONTAINER=$(docker create charon:pr-${{ github.sha }})
|
||||
docker cp ${CONTAINER}:/app/charon ./charon_binary || true
|
||||
docker rm ${CONTAINER} || true
|
||||
|
||||
- name: Run Trivy filesystem scan on `charon` (fail PR on HIGH/CRITICAL)
|
||||
run: |
|
||||
docker run --rm -v $HOME/.cache/trivy:/root/.cache/trivy -v $PWD:/workdir aquasec/trivy:latest fs --exit-code 1 --severity CRITICAL,HIGH /workdir/charon_binary
|
||||
shell: bash
|
||||
11
.github/workflows/docs-to-issues.yml
vendored
11
.github/workflows/docs-to-issues.yml
vendored
@@ -17,13 +17,20 @@ on:
|
||||
dry_run:
|
||||
description: 'Dry run (no issues created)'
|
||||
required: false
|
||||
default: 'false'
|
||||
default: false
|
||||
type: boolean
|
||||
file_path:
|
||||
description: 'Specific file to process (optional)'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
NODE_VERSION: '24.12.0'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
issues: write
|
||||
@@ -44,7 +51,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
with:
|
||||
node-version: '24.12.0'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm install gray-matter
|
||||
|
||||
5
.github/workflows/docs.yml
vendored
5
.github/workflows/docs.yml
vendored
@@ -21,6 +21,9 @@ concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
NODE_VERSION: '24.12.0'
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build Documentation
|
||||
@@ -35,7 +38,7 @@ jobs:
|
||||
- name: 🔧 Set up Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
with:
|
||||
node-version: '24.12.0'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
# Step 3: Create a beautiful docs site structure
|
||||
- name: 📝 Build documentation site
|
||||
|
||||
@@ -7,6 +7,10 @@ on:
|
||||
- cron: '0 2 * * *' # daily at 02:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
|
||||
4
.github/workflows/history-rewrite-tests.yml
vendored
4
.github/workflows/history-rewrite-tests.yml
vendored
@@ -9,6 +9,10 @@ on:
|
||||
paths:
|
||||
- 'scripts/history-rewrite/**'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
4
.github/workflows/pr-checklist.yml
vendored
4
.github/workflows/pr-checklist.yml
vendored
@@ -4,6 +4,10 @@ on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
validate:
|
||||
name: Validate history-rewrite checklist (conditional)
|
||||
|
||||
9
.github/workflows/propagate-changes.yml
vendored
9
.github/workflows/propagate-changes.yml
vendored
@@ -6,6 +6,13 @@ on:
|
||||
- main
|
||||
- development
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
NODE_VERSION: '24.12.0'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
@@ -20,7 +27,7 @@ jobs:
|
||||
- name: Set up Node (for github-script)
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
with:
|
||||
node-version: '24.12.0'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Propagate Changes
|
||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8
|
||||
|
||||
12
.github/workflows/quality-checks.yml
vendored
12
.github/workflows/quality-checks.yml
vendored
@@ -6,6 +6,14 @@ on:
|
||||
pull_request:
|
||||
branches: [ main, development ]
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.25.5'
|
||||
NODE_VERSION: '24.12.0'
|
||||
|
||||
jobs:
|
||||
backend-quality:
|
||||
name: Backend (Go)
|
||||
@@ -16,7 +24,7 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
cache-dependency-path: backend/go.sum
|
||||
|
||||
- name: Repo health check
|
||||
@@ -89,7 +97,7 @@ jobs:
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
|
||||
with:
|
||||
node-version: '24.12.0'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
cache: 'npm'
|
||||
cache-dependency-path: frontend/package-lock.json
|
||||
|
||||
|
||||
15
.github/workflows/release-goreleaser.yml
vendored
15
.github/workflows/release-goreleaser.yml
vendored
@@ -5,6 +5,14 @@ on:
|
||||
tags:
|
||||
- 'v*'
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
GO_VERSION: '1.25.5'
|
||||
NODE_VERSION: '24.12.0'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
packages: write
|
||||
@@ -26,12 +34,12 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6
|
||||
with:
|
||||
go-version: '1.25.5'
|
||||
go-version: ${{ env.GO_VERSION }}
|
||||
|
||||
- name: Set up Node.js
|
||||
uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6
|
||||
with:
|
||||
node-version: '24.12.0'
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
- name: Build Frontend
|
||||
working-directory: frontend
|
||||
@@ -43,7 +51,8 @@ jobs:
|
||||
npm run build
|
||||
|
||||
- name: Install Cross-Compilation Tools (Zig)
|
||||
uses: goto-bus-stop/setup-zig@v2
|
||||
# Security: Pinned to full SHA for supply chain security
|
||||
uses: goto-bus-stop/setup-zig@abea47f85e598557f500fa1fd2ab7464fcb39406 # v2
|
||||
with:
|
||||
version: 0.13.0
|
||||
|
||||
|
||||
6
.github/workflows/renovate.yml
vendored
6
.github/workflows/renovate.yml
vendored
@@ -5,6 +5,10 @@ on:
|
||||
- cron: '0 5 * * *' # daily 05:00 UTC
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}
|
||||
cancel-in-progress: false
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
@@ -20,7 +24,7 @@ jobs:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Renovate
|
||||
uses: renovatebot/github-action@822441559e94f98b67b82d97ab89fe3003b0a247 # v44.2.0
|
||||
uses: renovatebot/github-action@f7fad228a053c69a98e24f8e4f6cf40db8f61e08 # v44.2.1
|
||||
with:
|
||||
configurationFile: .github/renovate.json
|
||||
token: ${{ secrets.RENOVATE_TOKEN }}
|
||||
|
||||
4
.github/workflows/repo-health.yml
vendored
4
.github/workflows/repo-health.yml
vendored
@@ -7,6 +7,10 @@ on:
|
||||
types: [opened, synchronize, reopened]
|
||||
workflow_dispatch: {}
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
repo_health:
|
||||
name: Repo health
|
||||
|
||||
@@ -11,6 +11,10 @@ on:
|
||||
type: boolean
|
||||
default: true
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: false
|
||||
|
||||
env:
|
||||
REGISTRY: ghcr.io
|
||||
IMAGE_NAME: ${{ github.repository_owner }}/charon
|
||||
@@ -37,7 +41,7 @@ jobs:
|
||||
uses: docker/setup-qemu-action@c7c53464625b32c7a7e944ae62b3e17d2b600130 # v3.7.0
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
|
||||
- name: Resolve Caddy base digest
|
||||
id: caddy
|
||||
@@ -97,7 +101,7 @@ jobs:
|
||||
severity: 'CRITICAL,HIGH,MEDIUM'
|
||||
|
||||
- name: Upload Trivy results to GitHub Security
|
||||
uses: github/codeql-action/upload-sarif@1b168cd39490f61582a9beae412bb7057a6b2c4e # v4.31.8
|
||||
uses: github/codeql-action/upload-sarif@5d4e8d1aca955e8d8589aabd499c5cae939e33c7 # v4.31.9
|
||||
with:
|
||||
sarif_file: 'trivy-weekly-results.sarif'
|
||||
|
||||
|
||||
6
.github/workflows/waf-integration.yml
vendored
6
.github/workflows/waf-integration.yml
vendored
@@ -20,6 +20,10 @@ on:
|
||||
# Allow manual trigger
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
waf-integration:
|
||||
name: Coraza WAF Integration
|
||||
@@ -30,7 +34,7 @@ jobs:
|
||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1
|
||||
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0
|
||||
|
||||
- name: Build Docker image
|
||||
run: |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user