Skip to content

Commit 88dbc84

Browse files
committed
chore(tests): Integrate VCR tests in the CI and introduce a Makefile
Issue: APPAI-157
1 parent 675a44a commit 88dbc84

File tree

4 files changed

+112
-29
lines changed

4 files changed

+112
-29
lines changed

.github/workflows/ci.yml

Lines changed: 31 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,9 +56,9 @@ jobs:
5656
- name: Run mypy
5757
run: uv run mypy packages/
5858

59-
test:
59+
test-unit:
6060
runs-on: ubuntu-latest
61-
name: Run Tests
61+
name: Run Unit Tests
6262

6363
steps:
6464
- uses: actions/checkout@v4
@@ -76,8 +76,35 @@ jobs:
7676
- name: Install dependencies
7777
run: uv sync --all-groups
7878

79-
- name: Run tests
80-
run: uv run pytest tests/
79+
- name: Run unit tests
80+
env:
81+
ENABLE_LOCAL_OAUTH: "false"
82+
run: make test-unit
83+
84+
test-vcr:
85+
runs-on: ubuntu-latest
86+
name: Run VCR Tests
87+
88+
steps:
89+
- uses: actions/checkout@v4
90+
91+
- name: Set up Python
92+
uses: actions/setup-python@v5
93+
with:
94+
python-version: '3.13'
95+
96+
- name: Install uv
97+
uses: astral-sh/setup-uv@v4
98+
with:
99+
enable-cache: true
100+
101+
- name: Install dependencies
102+
run: uv sync --all-groups
103+
104+
- name: Run VCR tests
105+
env:
106+
ENABLE_LOCAL_OAUTH: "false"
107+
run: make test-vcr
81108

82109
docker-build:
83110
runs-on: ubuntu-latest

Makefile

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
SHELL := /bin/bash
2+
.PHONY: test test-vcr test-unit test-with-env test-vcr-with-env lint format typecheck
3+
4+
# =============================================================================
5+
# CI commands (no .env sourcing)
6+
# =============================================================================
7+
8+
# Run all tests
9+
test:
10+
ENABLE_LOCAL_OAUTH=false uv run pytest
11+
12+
# Run VCR cassette tests only (tests marked with @pytest.mark.vcr_test)
13+
test-vcr:
14+
ENABLE_LOCAL_OAUTH=false uv run pytest -m vcr_test -v
15+
16+
# Run unit tests (tests NOT marked with @pytest.mark.vcr_test)
17+
test-unit:
18+
ENABLE_LOCAL_OAUTH=false uv run pytest -m "not vcr_test"
19+
20+
# =============================================================================
21+
# Local dev commands (sources .env for API key)
22+
# =============================================================================
23+
24+
# Run all tests with .env loaded
25+
test-with-env:
26+
set -a && source .env && set +a && make test
27+
28+
# Run VCR tests with .env loaded (for recording cassettes)
29+
test-vcr-with-env:
30+
set -a && source .env && set +a && make test-vcr
31+
32+
# =============================================================================
33+
# Code quality
34+
# =============================================================================
35+
36+
# Linting
37+
lint:
38+
uv run ruff check .
39+
40+
# Format code
41+
format:
42+
uv run ruff format .
43+
44+
# Type checking
45+
typecheck:
46+
uv run mypy .

tests/cassettes/README.md

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
This directory contains VCR cassettes - recorded HTTP interactions with the GitGuardian API.
44

5+
> **Important**: Cassettes are **recorded locally** and committed to the repository. CI replays from these committed cassettes without requiring API credentials. Developers should **periodically re-record cassettes** to keep them in sync with API changes.
6+
7+
## Recording Workflow
8+
9+
```
10+
Local (with API key) CI (no API key)
11+
┌───────────────────────────┐ ┌─────────────────────┐
12+
│ make test-vcr-with-env │ ───▶ │ make test-vcr │
13+
│ (real API calls) │ git │ (replay only) │
14+
└───────────────────────────┘ push └─────────────────────┘
15+
```
16+
517
## What are VCR Cassettes?
618

719
VCR cassettes record real HTTP requests and responses the first time a test runs, then replay those recorded responses on subsequent runs. This provides:
@@ -113,11 +125,12 @@ version: 1
113125
114126
Cassettes are **automatically scrubbed** of sensitive data:
115127
116-
- `Authorization` headers are filtered
117-
- `X-Api-Key` headers are filtered
118-
- Query parameters `api_key` and `token` are filtered
128+
- Request headers are filtered (only safe headers like `content-type` are kept)
129+
- Response body fields are redacted: `secret_key`, `access_token_id`, `token`, `api_key`, `password`, `secret`, `credential`, `share_url`
130+
- Share URLs containing incident tokens are redacted
131+
- POST data parameters are filtered: `api_key`, `secret`, `client_id`, `client_secret`, `token`, `password`
119132

120-
However, **always review cassettes before committing** to ensure no sensitive data remains in response bodies.
133+
Redacted values appear as `[REDACTED]` in cassette files.
121134

122135
## Replay Mode
123136

@@ -128,23 +141,23 @@ By default, VCR uses `record_mode="once"`:
128141

129142
## Troubleshooting
130143

131-
### "GITGUARDIAN_API_KEY is not set" warning
132-
Set the environment variable before running tests:
133-
```bash
134-
export GITGUARDIAN_API_KEY="your-token"
135-
```
136-
137-
### Test fails with 401 Unauthorized
144+
### Test fails with 401 Unauthorized (when recording)
138145
Your API key may be invalid or expired. Generate a new PAT from the GitGuardian dashboard.
139146

140147
### Cassette not being created
141-
1. Ensure `record_mode` is set to `"once"` (default)
148+
1. Ensure `GITGUARDIAN_API_KEY` is set in your `.env` file
142149
2. Check that the cassettes directory exists
143150
3. Verify network connectivity to the API
144151

145152
### Tests fail after API changes
146-
Delete the cassette and re-record:
153+
Delete the cassette and re-record locally:
147154
```bash
148155
rm tests/cassettes/test_name.yaml
149-
ENABLE_LOCAL_OAUTH=false uv run pytest tests/path::test_name -v
156+
make test-vcr-with-env
157+
```
158+
159+
### Re-record all cassettes
160+
```bash
161+
rm tests/cassettes/*.yaml
162+
make test-vcr-with-env
150163
```

tests/conftest.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -130,12 +130,13 @@ def _before_record_response(response):
130130
@pytest.fixture(scope="session")
131131
def real_client():
132132
"""
133-
Create a real GitGuardianClient for recording cassettes.
133+
Create a real GitGuardianClient for recording/replaying cassettes.
134134
135-
This fixture creates a client that makes actual API calls.
136-
Use this with VCR cassettes to record real HTTP interactions.
135+
This fixture creates a client for use with VCR cassettes.
136+
- When cassettes exist: VCR replays recorded responses (no real API calls)
137+
- When recording new cassettes: Requires GITGUARDIAN_API_KEY env var
137138
138-
Environment variables required for recording:
139+
Environment variables (only needed for recording new cassettes):
139140
- GITGUARDIAN_API_KEY: Your GitGuardian API key (Personal Access Token)
140141
- GITGUARDIAN_URL: (Optional) Custom GitGuardian URL, defaults to SaaS
141142
@@ -148,13 +149,9 @@ async def test_something(real_client):
148149
"""
149150
from gg_api_core.client import GitGuardianClient
150151

151-
api_key = os.getenv("GITGUARDIAN_API_KEY")
152-
if not api_key:
153-
raise ValueError(
154-
"GITGUARDIAN_API_KEY is not set, recording VCR cassettes won't work. "
155-
"Set this environment variable to record new cassettes."
156-
)
157-
152+
# Use real key if available, otherwise use dummy key for cassette replay
153+
# VCR will intercept requests and replay from cassettes, so the key doesn't matter
154+
api_key = os.getenv("GITGUARDIAN_API_KEY", "dummy-key-for-cassette-replay")
158155
gitguardian_url = os.getenv("GITGUARDIAN_URL", "https://dashboard.gitguardian.com")
159156

160157
# Create client with PAT (bypasses OAuth)

0 commit comments

Comments
 (0)