Skip to content

Commit 884b3db

Browse files
authored
Merge pull request #11 from Oppskrift/002-user-auth
002 user auth
2 parents 3b845d4 + 9dbadac commit 884b3db

128 files changed

Lines changed: 16872 additions & 2617 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.env.example

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,14 @@ POSTGRES_PASSWORD=oppskrift
1313
POSTGRES_DB=oppskrift
1414

1515
# JWT Secret (REQUIRED - minimum 32 characters)
16-
# Generate with: openssl rand -base64 32
16+
# Generate with: openssl rand -base64 48
1717
JWT_SECRET=change-me-in-production-min-32-chars
1818

19+
# TOTP Encryption Key (REQUIRED in production - 64 hex chars = 32 bytes)
20+
# Generate with: openssl rand -hex 32
21+
# Used to encrypt TOTP secrets stored in database
22+
TOTP_ENCRYPTION_KEY=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
23+
1924
# S3 Bucket (REQUIRED)
2025
S3_BUCKET=oppskrift
2126

@@ -42,3 +47,34 @@ BASE_URL=http://localhost:3000
4247
# Federation
4348
INSTANCE_DOMAIN=localhost:3000
4449
INSTANCE_NAME=Oppskrift Dev
50+
51+
# =============================================================================
52+
# AUTHENTICATION (Optional - have sensible defaults)
53+
# =============================================================================
54+
55+
# Session settings
56+
SESSION_EXPIRY_DAYS=7
57+
58+
# Rate limiting
59+
RATE_LIMIT_LOGIN_PER_IP=10
60+
RATE_LIMIT_LOGIN_PER_ACCOUNT=5
61+
LOCKOUT_DURATION_MINUTES=15
62+
63+
# =============================================================================
64+
# EMAIL / SMTP (Optional - email features disabled if not configured)
65+
# =============================================================================
66+
67+
# For local development with Mailpit (docker-compose up mailpit)
68+
# View emails at http://localhost:8025
69+
SMTP_HOST=localhost
70+
SMTP_PORT=1025
71+
EMAIL_FROM_ADDRESS=noreply@localhost
72+
EMAIL_FROM_NAME=Oppskrift Dev
73+
74+
# For production, use a real SMTP provider:
75+
# SMTP_HOST=smtp.example.com
76+
# SMTP_PORT=587
77+
# SMTP_USER=noreply@oppskrift.example.com
78+
# SMTP_PASSWORD=your-smtp-password
79+
# EMAIL_FROM_ADDRESS=noreply@oppskrift.example.com
80+
# EMAIL_FROM_NAME=Oppskrift

.githooks/pre-commit

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env bash
22
# Pre-commit hook for Oppskrift
3-
# Runs formatting and linting checks before allowing commits
3+
# Runs formatting, linting, and secret scanning before allowing commits
44

55
set -e
66

@@ -12,6 +12,20 @@ NC='\033[0m' # No Color
1212

1313
echo "Running pre-commit checks..."
1414

15+
# Gitleaks secret scanning (on staged files only)
16+
if command -v gitleaks &> /dev/null; then
17+
echo "Running gitleaks..."
18+
if gitleaks protect --staged --config .gitleaks.toml; then
19+
echo -e "${GREEN}Gitleaks OK${NC}"
20+
else
21+
echo -e "${RED}Gitleaks found potential secrets in staged files${NC}"
22+
exit 1
23+
fi
24+
else
25+
echo -e "${YELLOW}Warning: gitleaks not installed, skipping secret scan${NC}"
26+
echo "Install with: brew install gitleaks (macOS) or download from GitHub"
27+
fi
28+
1529
# Check if docker or podman is available for database
1630
if ! command -v docker &> /dev/null && ! command -v podman &> /dev/null; then
1731
echo -e "${YELLOW}Warning: Docker/Podman not available, skipping database-dependent checks${NC}"

.github/workflows/ci.yml

Lines changed: 30 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -9,53 +9,12 @@ on:
99
env:
1010
CARGO_TERM_COLOR: always
1111
RUST_BACKTRACE: 1
12-
DATABASE_URL: postgres://oppskrift:oppskrift@localhost:5432/oppskrift
12+
SQLX_OFFLINE: true
13+
# Test-only encryption key for 2FA (64 hex chars = 32 bytes)
14+
TOTP_ENCRYPTION_KEY: "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
1315

1416
jobs:
15-
# Build first - all other jobs depend on this
16-
build:
17-
name: Build
18-
runs-on: ubuntu-latest
19-
services:
20-
postgres:
21-
image: postgres:15-alpine
22-
env:
23-
POSTGRES_USER: oppskrift
24-
POSTGRES_PASSWORD: oppskrift
25-
POSTGRES_DB: oppskrift
26-
ports:
27-
- 5432:5432
28-
options: >-
29-
--health-cmd pg_isready
30-
--health-interval 10s
31-
--health-timeout 5s
32-
--health-retries 5
33-
steps:
34-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
35-
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
36-
with:
37-
toolchain: stable
38-
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
39-
with:
40-
cache-all-crates: "true"
41-
shared-key: "build"
42-
- name: Install sqlx-cli
43-
run: cargo install sqlx-cli --no-default-features --features postgres
44-
- name: Run migrations
45-
run: sqlx migrate run
46-
- name: Build
47-
run: cargo build --all-features
48-
# Cache build artifacts for other jobs
49-
- name: Save build artifacts
50-
uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
51-
with:
52-
path: |
53-
target/
54-
~/.cargo/registry/
55-
~/.cargo/git/
56-
key: build-${{ github.sha }}
57-
58-
# Format check - no dependencies, fast
17+
# Fast checks - no dependencies, run in parallel
5918
fmt:
6019
name: Format
6120
runs-on: ubuntu-latest
@@ -67,51 +26,38 @@ jobs:
6726
components: rustfmt
6827
- run: cargo fmt --all -- --check
6928

70-
# Clippy - depends on build, reuses build cache
71-
clippy:
72-
name: Clippy
73-
needs: build
29+
# Build and lint - uses SQLX_OFFLINE, no database needed
30+
check:
31+
name: Check & Clippy
7432
runs-on: ubuntu-latest
75-
services:
76-
postgres:
77-
image: postgres:15-alpine
78-
env:
79-
POSTGRES_USER: oppskrift
80-
POSTGRES_PASSWORD: oppskrift
81-
POSTGRES_DB: oppskrift
82-
ports:
83-
- 5432:5432
84-
options: >-
85-
--health-cmd pg_isready
86-
--health-interval 10s
87-
--health-timeout 5s
88-
--health-retries 5
8933
steps:
9034
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
9135
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
9236
with:
9337
toolchain: stable
9438
components: clippy
95-
# Restore build artifacts from build job
96-
- name: Restore build artifacts
97-
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
39+
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
40+
- name: Build
41+
run: cargo build --all-features
42+
- name: Clippy
43+
run: cargo clippy --all-features -- -D warnings
44+
# Save artifacts for test job
45+
- uses: actions/cache/save@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
9846
with:
9947
path: |
10048
target/
10149
~/.cargo/registry/
10250
~/.cargo/git/
10351
key: build-${{ github.sha }}
104-
- name: Install sqlx-cli
105-
run: cargo install sqlx-cli --no-default-features --features postgres
106-
- name: Run migrations
107-
run: sqlx migrate run
108-
- run: cargo clippy --all-features -- -D warnings
10952

110-
# Tests - depends on build, reuses build cache
53+
# Tests need real database
11154
test:
11255
name: Test
113-
needs: build
56+
needs: check
11457
runs-on: ubuntu-latest
58+
env:
59+
DATABASE_URL: postgres://oppskrift:oppskrift@localhost:5432/oppskrift
60+
SQLX_OFFLINE: false
11561
services:
11662
postgres:
11763
image: postgres:15-alpine
@@ -131,27 +77,23 @@ jobs:
13177
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
13278
with:
13379
toolchain: stable
134-
# Restore build artifacts from build job
135-
- name: Restore build artifacts
136-
uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
80+
- uses: actions/cache/restore@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
13781
with:
13882
path: |
13983
target/
14084
~/.cargo/registry/
14185
~/.cargo/git/
14286
key: build-${{ github.sha }}
87+
- name: Cache sqlx-cli
88+
id: cache-sqlx
89+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
90+
with:
91+
path: ~/.cargo/bin/sqlx
92+
key: sqlx-cli-0.8
14393
- name: Install sqlx-cli
144-
run: cargo install sqlx-cli --no-default-features --features postgres
94+
if: steps.cache-sqlx.outputs.cache-hit != 'true'
95+
run: cargo install sqlx-cli --no-default-features --features postgres --locked
14596
- name: Run migrations
14697
run: sqlx migrate run
147-
- run: cargo test --all-features
148-
149-
# Security audit - no dependencies, can run in parallel
150-
audit:
151-
name: Security Audit
152-
runs-on: ubuntu-latest
153-
steps:
154-
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
155-
- uses: rustsec/audit-check@69366f33c96575abad1ee0dba8212993eecbe998 # v2.0.0
156-
with:
157-
token: ${{ secrets.GITHUB_TOKEN }}
98+
- name: Run tests
99+
run: cargo test --all-features

.github/workflows/security.yml

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
name: Security
2+
3+
on:
4+
push:
5+
branches: [main, develop]
6+
pull_request:
7+
branches: [main]
8+
schedule:
9+
# Daily security scan at 6 AM UTC
10+
- cron: '0 6 * * *'
11+
12+
env:
13+
SQLX_OFFLINE: true
14+
15+
jobs:
16+
# All security checks in one job to reduce overhead
17+
security:
18+
name: Security Checks
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
22+
with:
23+
fetch-depth: 0
24+
25+
- uses: dtolnay/rust-toolchain@f7ccc83f9ed1e5b9c81d8a67d7ad1a747e22a561 # master
26+
with:
27+
toolchain: stable
28+
components: clippy
29+
30+
- uses: Swatinem/rust-cache@779680da715d629ac1d338a641029a2f4372abb5 # v2.8.2
31+
32+
# Gitleaks - secret scanning
33+
- name: Install Gitleaks
34+
run: |
35+
curl -sSL https://github.com/gitleaks/gitleaks/releases/download/v8.21.2/gitleaks_8.21.2_linux_x64.tar.gz -o gitleaks.tar.gz
36+
tar xzf gitleaks.tar.gz
37+
chmod +x gitleaks
38+
39+
- name: Secret Scan
40+
run: ./gitleaks detect --source . --config .gitleaks.toml --verbose
41+
42+
# Cargo audit - dependency vulnerabilities
43+
- name: Cache cargo-audit
44+
id: cache-audit
45+
uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0
46+
with:
47+
path: ~/.cargo/bin/cargo-audit
48+
key: cargo-audit-0.21
49+
- name: Install cargo-audit
50+
if: steps.cache-audit.outputs.cache-hit != 'true'
51+
run: cargo install cargo-audit --locked
52+
53+
- name: Dependency Audit
54+
run: cargo audit --deny warnings --deny unmaintained --deny yanked
55+
56+
# Security-focused clippy lints (warnings, not errors)
57+
- name: Security Lints
58+
run: |
59+
cargo clippy --all-features -- \
60+
-W clippy::unwrap_used \
61+
-W clippy::expect_used \
62+
-D unsafe_code \
63+
-W clippy::todo \
64+
-W clippy::unimplemented

.gitleaks.toml

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,50 @@
1-
# Gitleaks configuration for Oppskrift
2-
title = "Oppskrift Gitleaks Configuration"
1+
# Gitleaks configuration
2+
# https://github.com/gitleaks/gitleaks
33

4-
[allowlist]
5-
description = "Allowed patterns"
6-
paths = [
7-
".env.example",
8-
"docker-compose.yml",
9-
]
4+
title = "Oppskrift Gitleaks Config"
5+
6+
[extend]
7+
useDefault = true
108

11-
[[rules]]
12-
id = "jwt-secret"
13-
description = "JWT Secret"
14-
regex = '''JWT_SECRET\s*=\s*["']?[^"'\s]{33,}["']?'''
15-
keywords = ["jwt_secret", "JWT_SECRET"]
9+
# Allowlist for false positives
10+
[allowlist]
11+
description = "Allowlisted patterns and paths"
1612

17-
[[rules]]
18-
id = "database-url"
19-
description = "Database URL with credentials"
20-
regex = '''postgres://[^:]+:[^@]+@'''
21-
keywords = ["DATABASE_URL", "postgres://"]
13+
# Placeholder/example values in documentation
14+
regexes = [
15+
# Placeholder passwords in docs
16+
'''your-smtp-password''',
17+
'''your-256-bit-secret-here''',
18+
# Template variables
19+
'''\$\{DB_PASSWORD\}''',
20+
'''\$\{.*_SECRET\}''',
21+
# Test credentials (explicitly fake)
22+
'''test:test@''',
23+
# Fake argon2 hashes in tests
24+
'''fakesalt''',
25+
'''fakehash''',
26+
# Example/truncated JWTs in docs
27+
'''eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9\.\.\.''',
28+
# Test assertions checking key format (not actual keys)
29+
'''starts_with\("-----BEGIN''',
30+
]
2231

23-
[[rules]]
24-
id = "s3-secret"
25-
description = "S3 Secret Access Key"
26-
regex = '''S3_SECRET_ACCESS_KEY\s*=\s*["']?[^"'\s]+["']?'''
27-
keywords = ["S3_SECRET", "secret_access_key"]
32+
paths = [
33+
# Documentation with example configs
34+
'''DEPLOYMENT\.md''',
35+
'''quickstart\.md''',
36+
'''testing\.md''',
37+
# Scripts that generate secrets (contain templates, not real secrets)
38+
'''scripts/generate-secrets\.sh''',
39+
# Test files with fake hashes
40+
'''tests/timing_test\.rs''',
41+
'''tests/enumeration_test\.rs''',
42+
# Example env file
43+
'''\.env\.example''',
44+
# Crypto module tests (assertions checking key format)
45+
'''src/lib/crypto\.rs''',
46+
# OSK templates with example tokens
47+
'''\.osk/domaines/.*\.md''',
48+
# CI workflows with test-only keys
49+
'''\.github/workflows/.*\.yml''',
50+
]

0 commit comments

Comments
 (0)