mirror of
https://github.com/juanfont/headscale.git
synced 2026-02-27 18:07:37 +01:00
Compare commits
1 Commits
main
...
bug_report
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c4cb0d2126 |
@@ -1,870 +0,0 @@
|
|||||||
---
|
|
||||||
name: headscale-integration-tester
|
|
||||||
description: Use this agent when you need to execute, analyze, or troubleshoot Headscale integration tests. This includes running specific test scenarios, investigating test failures, interpreting test artifacts, validating end-to-end functionality, or ensuring integration test quality before releases. Examples: <example>Context: User has made changes to the route management code and wants to validate the changes work correctly. user: 'I've updated the route advertisement logic in poll.go. Can you run the relevant integration tests to make sure everything still works?' assistant: 'I'll use the headscale-integration-tester agent to run the subnet routing integration tests and analyze the results.' <commentary>Since the user wants to validate route-related changes with integration tests, use the headscale-integration-tester agent to execute the appropriate tests and analyze results.</commentary></example> <example>Context: A CI pipeline integration test is failing and the user needs help understanding why. user: 'The TestSubnetRouterMultiNetwork test is failing in CI. The logs show some timing issues but I can't figure out what's wrong.' assistant: 'Let me use the headscale-integration-tester agent to analyze the test failure and examine the artifacts.' <commentary>Since this involves analyzing integration test failures and interpreting test artifacts, use the headscale-integration-tester agent to investigate the issue.</commentary></example>
|
|
||||||
color: green
|
|
||||||
---
|
|
||||||
|
|
||||||
You are a specialist Quality Assurance Engineer with deep expertise in Headscale's integration testing system. You understand the Docker-based test infrastructure, real Tailscale client interactions, and the complex timing considerations involved in end-to-end network testing.
|
|
||||||
|
|
||||||
## Integration Test System Overview
|
|
||||||
|
|
||||||
The Headscale integration test system uses Docker containers running real Tailscale clients against a Headscale server. Tests validate end-to-end functionality including routing, ACLs, node lifecycle, and network coordination. The system is built around the `hi` (Headscale Integration) test runner in `cmd/hi/`.
|
|
||||||
|
|
||||||
## Critical Test Execution Knowledge
|
|
||||||
|
|
||||||
### System Requirements and Setup
|
|
||||||
```bash
|
|
||||||
# ALWAYS run this first to verify system readiness
|
|
||||||
go run ./cmd/hi doctor
|
|
||||||
```
|
|
||||||
This command verifies:
|
|
||||||
- Docker installation and daemon status
|
|
||||||
- Go environment setup
|
|
||||||
- Required container images availability
|
|
||||||
- Sufficient disk space (critical - tests generate ~100MB logs per run)
|
|
||||||
- Network configuration
|
|
||||||
|
|
||||||
### Test Execution Patterns
|
|
||||||
|
|
||||||
**CRITICAL TIMEOUT REQUIREMENTS**:
|
|
||||||
- **NEVER use bash `timeout` command** - this can cause test failures and incomplete cleanup
|
|
||||||
- **ALWAYS use the built-in `--timeout` flag** with generous timeouts (minimum 15 minutes)
|
|
||||||
- **Increase timeout if tests ever time out** - infrastructure issues require longer timeouts
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Single test execution (recommended for development)
|
|
||||||
# ALWAYS use --timeout flag with minimum 15 minutes (900s)
|
|
||||||
go run ./cmd/hi run "TestSubnetRouterMultiNetwork" --timeout=900s
|
|
||||||
|
|
||||||
# Database-heavy tests require PostgreSQL backend and longer timeouts
|
|
||||||
go run ./cmd/hi run "TestExpireNode" --postgres --timeout=1800s
|
|
||||||
|
|
||||||
# Pattern matching for related tests - use longer timeout for multiple tests
|
|
||||||
go run ./cmd/hi run "TestSubnet*" --timeout=1800s
|
|
||||||
|
|
||||||
# Long-running individual tests need extended timeouts
|
|
||||||
go run ./cmd/hi run "TestNodeOnlineStatus" --timeout=2100s # Runs for 12+ minutes
|
|
||||||
|
|
||||||
# Full test suite (CI/validation only) - very long timeout required
|
|
||||||
go test ./integration -timeout 45m
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timeout Guidelines by Test Type**:
|
|
||||||
- **Basic functionality tests**: `--timeout=900s` (15 minutes minimum)
|
|
||||||
- **Route/ACL tests**: `--timeout=1200s` (20 minutes)
|
|
||||||
- **HA/failover tests**: `--timeout=1800s` (30 minutes)
|
|
||||||
- **Long-running tests**: `--timeout=2100s` (35 minutes)
|
|
||||||
- **Full test suite**: `-timeout 45m` (45 minutes)
|
|
||||||
|
|
||||||
**NEVER do this**:
|
|
||||||
```bash
|
|
||||||
# ❌ FORBIDDEN: Never use bash timeout command
|
|
||||||
timeout 300 go run ./cmd/hi run "TestName"
|
|
||||||
|
|
||||||
# ❌ FORBIDDEN: Too short timeout will cause failures
|
|
||||||
go run ./cmd/hi run "TestName" --timeout=60s
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Categories and Timing Expectations
|
|
||||||
- **Fast tests** (<2 min): Basic functionality, CLI operations
|
|
||||||
- **Medium tests** (2-5 min): Route management, ACL validation
|
|
||||||
- **Slow tests** (5+ min): Node expiration, HA failover
|
|
||||||
- **Long-running tests** (10+ min): `TestNodeOnlineStatus` runs for 12 minutes
|
|
||||||
|
|
||||||
**CONCURRENT EXECUTION**: Multiple tests CAN run simultaneously. Each test run gets a unique Run ID for isolation. See "Concurrent Execution and Run ID Isolation" section below.
|
|
||||||
|
|
||||||
## Test Artifacts and Log Analysis
|
|
||||||
|
|
||||||
### Artifact Structure
|
|
||||||
All test runs save comprehensive artifacts to `control_logs/TIMESTAMP-ID/`:
|
|
||||||
```
|
|
||||||
control_logs/20250713-213106-iajsux/
|
|
||||||
├── hs-testname-abc123.stderr.log # Headscale server error logs
|
|
||||||
├── hs-testname-abc123.stdout.log # Headscale server output logs
|
|
||||||
├── hs-testname-abc123.db # Database snapshot for post-mortem
|
|
||||||
├── hs-testname-abc123_metrics.txt # Prometheus metrics dump
|
|
||||||
├── hs-testname-abc123-mapresponses/ # Protocol-level debug data
|
|
||||||
├── ts-client-xyz789.stderr.log # Tailscale client error logs
|
|
||||||
├── ts-client-xyz789.stdout.log # Tailscale client output logs
|
|
||||||
└── ts-client-xyz789_status.json # Client network status dump
|
|
||||||
```
|
|
||||||
|
|
||||||
### Log Analysis Priority Order
|
|
||||||
When tests fail, examine artifacts in this specific order:
|
|
||||||
|
|
||||||
1. **Headscale server stderr logs** (`hs-*.stderr.log`): Look for errors, panics, database issues, policy evaluation failures
|
|
||||||
2. **Tailscale client stderr logs** (`ts-*.stderr.log`): Check for authentication failures, network connectivity issues
|
|
||||||
3. **MapResponse JSON files**: Protocol-level debugging for network map generation issues
|
|
||||||
4. **Client status dumps** (`*_status.json`): Network state and peer connectivity information
|
|
||||||
5. **Database snapshots** (`.db` files): For data consistency and state persistence issues
|
|
||||||
|
|
||||||
## Concurrent Execution and Run ID Isolation
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
|
|
||||||
The integration test system supports running multiple tests concurrently on the same Docker daemon. Each test run is isolated through a unique Run ID that ensures containers, networks, and cleanup operations don't interfere with each other.
|
|
||||||
|
|
||||||
### Run ID Format and Usage
|
|
||||||
|
|
||||||
Each test run generates a unique Run ID in the format: `YYYYMMDD-HHMMSS-{6-char-hash}`
|
|
||||||
- Example: `20260109-104215-mdjtzx`
|
|
||||||
|
|
||||||
The Run ID is used for:
|
|
||||||
- **Container naming**: `ts-{runIDShort}-{version}-{hash}` (e.g., `ts-mdjtzx-1-74-fgdyls`)
|
|
||||||
- **Docker labels**: All containers get `hi.run-id={runID}` label
|
|
||||||
- **Log directories**: `control_logs/{runID}/`
|
|
||||||
- **Cleanup isolation**: Only containers with matching run ID are cleaned up
|
|
||||||
|
|
||||||
### Container Isolation Mechanisms
|
|
||||||
|
|
||||||
1. **Unique Container Names**: Each container includes the run ID for identification
|
|
||||||
2. **Docker Labels**: `hi.run-id` and `hi.test-type` labels on all containers
|
|
||||||
3. **Dynamic Port Allocation**: All ports use `{HostPort: "0"}` to let kernel assign free ports
|
|
||||||
4. **Per-Run Networks**: Network names include scenario hash for isolation
|
|
||||||
5. **Isolated Cleanup**: `killTestContainersByRunID()` only removes containers matching the run ID
|
|
||||||
|
|
||||||
### ⚠️ CRITICAL: Never Interfere with Other Test Runs
|
|
||||||
|
|
||||||
**FORBIDDEN OPERATIONS** when other tests may be running:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# ❌ NEVER do global container cleanup while tests are running
|
|
||||||
docker rm -f $(docker ps -q --filter "name=hs-")
|
|
||||||
docker rm -f $(docker ps -q --filter "name=ts-")
|
|
||||||
|
|
||||||
# ❌ NEVER kill all test containers
|
|
||||||
# This will destroy other agents' test sessions!
|
|
||||||
|
|
||||||
# ❌ NEVER prune all Docker resources during active tests
|
|
||||||
docker system prune -f # Only safe when NO tests are running
|
|
||||||
```
|
|
||||||
|
|
||||||
**SAFE OPERATIONS**:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# ✅ Clean up only YOUR test run's containers (by run ID)
|
|
||||||
# The test runner does this automatically via cleanup functions
|
|
||||||
|
|
||||||
# ✅ Clean stale (stopped/exited) containers only
|
|
||||||
# Pre-test cleanup only removes stopped containers, not running ones
|
|
||||||
|
|
||||||
# ✅ Check what's running before cleanup
|
|
||||||
docker ps --filter "name=headscale-test-suite" --format "{{.Names}}"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Running Concurrent Tests
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Start multiple tests in parallel - each gets unique run ID
|
|
||||||
go run ./cmd/hi run "TestPingAllByIP" &
|
|
||||||
go run ./cmd/hi run "TestACLAllowUserDst" &
|
|
||||||
go run ./cmd/hi run "TestOIDCAuthenticationPingAll" &
|
|
||||||
|
|
||||||
# Monitor running test suites
|
|
||||||
docker ps --filter "name=headscale-test-suite" --format "table {{.Names}}\t{{.Status}}"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Agent Session Isolation Rules
|
|
||||||
|
|
||||||
When working as an agent:
|
|
||||||
|
|
||||||
1. **Your run ID is unique**: Each test you start gets its own run ID
|
|
||||||
2. **Never clean up globally**: Only use run ID-specific cleanup
|
|
||||||
3. **Check before cleanup**: Verify no other tests are running if you need to prune resources
|
|
||||||
4. **Respect other sessions**: Other agents may have tests running concurrently
|
|
||||||
5. **Log directories are isolated**: Your artifacts are in `control_logs/{your-run-id}/`
|
|
||||||
|
|
||||||
### Identifying Your Containers
|
|
||||||
|
|
||||||
Your test containers can be identified by:
|
|
||||||
- The run ID in the container name
|
|
||||||
- The `hi.run-id` Docker label
|
|
||||||
- The test suite container: `headscale-test-suite-{your-run-id}`
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# List containers for a specific run ID
|
|
||||||
docker ps --filter "label=hi.run-id=20260109-104215-mdjtzx"
|
|
||||||
|
|
||||||
# Get your run ID from the test output
|
|
||||||
# Look for: "Run ID: 20260109-104215-mdjtzx"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Common Failure Patterns and Root Cause Analysis
|
|
||||||
|
|
||||||
### CRITICAL MINDSET: Code Issues vs Infrastructure Issues
|
|
||||||
|
|
||||||
**⚠️ IMPORTANT**: When tests fail, it is ALMOST ALWAYS a code issue with Headscale, NOT infrastructure problems. Do not immediately blame disk space, Docker issues, or timing unless you have thoroughly investigated the actual error logs first.
|
|
||||||
|
|
||||||
### Systematic Debugging Process
|
|
||||||
|
|
||||||
1. **Read the actual error message**: Don't assume - read the stderr logs completely
|
|
||||||
2. **Check Headscale server logs first**: Most issues originate from server-side logic
|
|
||||||
3. **Verify client connectivity**: Only after ruling out server issues
|
|
||||||
4. **Check timing patterns**: Use proper `EventuallyWithT` patterns
|
|
||||||
5. **Infrastructure as last resort**: Only blame infrastructure after code analysis
|
|
||||||
|
|
||||||
### Real Failure Patterns
|
|
||||||
|
|
||||||
#### 1. Timing Issues (Common but fixable)
|
|
||||||
```go
|
|
||||||
// ❌ Wrong: Immediate assertions after async operations
|
|
||||||
client.Execute([]string{"tailscale", "set", "--advertise-routes=10.0.0.0/24"})
|
|
||||||
nodes, _ := headscale.ListNodes()
|
|
||||||
require.Len(t, nodes[0].GetAvailableRoutes(), 1) // WILL FAIL
|
|
||||||
|
|
||||||
// ✅ Correct: Wait for async operations
|
|
||||||
client.Execute([]string{"tailscale", "set", "--advertise-routes=10.0.0.0/24"})
|
|
||||||
require.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Len(c, nodes[0].GetAvailableRoutes(), 1)
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "route should be advertised")
|
|
||||||
```
|
|
||||||
|
|
||||||
**Timeout Guidelines**:
|
|
||||||
- Route operations: 3-5 seconds
|
|
||||||
- Node state changes: 5-10 seconds
|
|
||||||
- Complex scenarios: 10-15 seconds
|
|
||||||
- Policy recalculation: 5-10 seconds
|
|
||||||
|
|
||||||
#### 2. NodeStore Synchronization Issues
|
|
||||||
Route advertisements must propagate through poll requests (`poll.go:420`). NodeStore updates happen at specific synchronization points after Hostinfo changes.
|
|
||||||
|
|
||||||
#### 3. Test Data Management Issues
|
|
||||||
```go
|
|
||||||
// ❌ Wrong: Assuming array ordering
|
|
||||||
require.Len(t, nodes[0].GetAvailableRoutes(), 1)
|
|
||||||
|
|
||||||
// ✅ Correct: Identify nodes by properties
|
|
||||||
expectedRoutes := map[string]string{"1": "10.33.0.0/16"}
|
|
||||||
for _, node := range nodes {
|
|
||||||
nodeIDStr := fmt.Sprintf("%d", node.GetId())
|
|
||||||
if route, shouldHaveRoute := expectedRoutes[nodeIDStr]; shouldHaveRoute {
|
|
||||||
// Test the specific node that should have the route
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. Database Backend Differences
|
|
||||||
SQLite vs PostgreSQL have different timing characteristics:
|
|
||||||
- Use `--postgres` flag for database-intensive tests
|
|
||||||
- PostgreSQL generally has more consistent timing
|
|
||||||
- Some race conditions only appear with specific backends
|
|
||||||
|
|
||||||
## Resource Management and Cleanup
|
|
||||||
|
|
||||||
### Disk Space Management
|
|
||||||
Tests consume significant disk space (~100MB per run):
|
|
||||||
```bash
|
|
||||||
# Check available space before running tests
|
|
||||||
df -h
|
|
||||||
|
|
||||||
# Clean up test artifacts periodically
|
|
||||||
rm -rf control_logs/older-timestamp-dirs/
|
|
||||||
|
|
||||||
# Clean Docker resources
|
|
||||||
docker system prune -f
|
|
||||||
docker volume prune -f
|
|
||||||
```
|
|
||||||
|
|
||||||
### Container Cleanup
|
|
||||||
- Successful tests clean up automatically
|
|
||||||
- Failed tests may leave containers running
|
|
||||||
- Manually clean if needed: `docker ps -a` and `docker rm -f <containers>`
|
|
||||||
|
|
||||||
## Advanced Debugging Techniques
|
|
||||||
|
|
||||||
### Protocol-Level Debugging
|
|
||||||
MapResponse JSON files in `control_logs/*/hs-*-mapresponses/` contain:
|
|
||||||
- Network topology as sent to clients
|
|
||||||
- Peer relationships and visibility
|
|
||||||
- Route distribution and primary route selection
|
|
||||||
- Policy evaluation results
|
|
||||||
|
|
||||||
### Database State Analysis
|
|
||||||
Use the database snapshots for post-mortem analysis:
|
|
||||||
```bash
|
|
||||||
# SQLite examination
|
|
||||||
sqlite3 control_logs/TIMESTAMP/hs-*.db
|
|
||||||
.tables
|
|
||||||
.schema nodes
|
|
||||||
SELECT * FROM nodes WHERE name LIKE '%problematic%';
|
|
||||||
```
|
|
||||||
|
|
||||||
### Performance Analysis
|
|
||||||
Prometheus metrics dumps show:
|
|
||||||
- Request latencies and error rates
|
|
||||||
- NodeStore operation timing
|
|
||||||
- Database query performance
|
|
||||||
- Memory usage patterns
|
|
||||||
|
|
||||||
## Test Development and Quality Guidelines
|
|
||||||
|
|
||||||
### Proper Test Patterns
|
|
||||||
```go
|
|
||||||
// Always use EventuallyWithT for async operations
|
|
||||||
require.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
// Test condition that may take time to become true
|
|
||||||
}, timeout, interval, "descriptive failure message")
|
|
||||||
|
|
||||||
// Handle node identification correctly
|
|
||||||
var targetNode *v1.Node
|
|
||||||
for _, node := range nodes {
|
|
||||||
if node.GetName() == expectedNodeName {
|
|
||||||
targetNode = node
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
require.NotNil(t, targetNode, "should find expected node")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Quality Validation Checklist
|
|
||||||
- ✅ Tests use `EventuallyWithT` for asynchronous operations
|
|
||||||
- ✅ Tests don't rely on array ordering for node identification
|
|
||||||
- ✅ Proper cleanup and resource management
|
|
||||||
- ✅ Tests handle both success and failure scenarios
|
|
||||||
- ✅ Timing assumptions are realistic for operations being tested
|
|
||||||
- ✅ Error messages are descriptive and actionable
|
|
||||||
|
|
||||||
## Real-World Test Failure Patterns from HA Debugging
|
|
||||||
|
|
||||||
### Infrastructure vs Code Issues - Detailed Examples
|
|
||||||
|
|
||||||
**INFRASTRUCTURE FAILURES (Rare but Real)**:
|
|
||||||
1. **DNS Resolution in Auth Tests**: `failed to resolve "hs-pingallbyip-jax97k": no DNS fallback candidates remain`
|
|
||||||
- **Pattern**: Client containers can't resolve headscale server hostname during logout
|
|
||||||
- **Detection**: Error messages specifically mention DNS/hostname resolution
|
|
||||||
- **Solution**: Docker networking reset, not code changes
|
|
||||||
|
|
||||||
2. **Container Creation Timeouts**: Test gets stuck during client container setup
|
|
||||||
- **Pattern**: Tests hang indefinitely at container startup phase
|
|
||||||
- **Detection**: No progress in logs for >2 minutes during initialization
|
|
||||||
- **Solution**: `docker system prune -f` and retry
|
|
||||||
|
|
||||||
3. **Docker Resource Exhaustion**: Too many concurrent tests overwhelming system
|
|
||||||
- **Pattern**: Container creation timeouts, OOM kills, slow test execution
|
|
||||||
- **Detection**: System load high, Docker daemon slow to respond
|
|
||||||
- **Solution**: Reduce number of concurrent tests, wait for completion before starting more
|
|
||||||
|
|
||||||
**CODE ISSUES (99% of failures)**:
|
|
||||||
1. **Route Approval Process Failures**: Routes not getting approved when they should be
|
|
||||||
- **Pattern**: Tests expecting approved routes but finding none
|
|
||||||
- **Detection**: `SubnetRoutes()` returns empty when `AnnouncedRoutes()` shows routes
|
|
||||||
- **Root Cause**: Auto-approval logic bugs, policy evaluation issues
|
|
||||||
|
|
||||||
2. **NodeStore Synchronization Issues**: State updates not propagating correctly
|
|
||||||
- **Pattern**: Route changes not reflected in NodeStore or Primary Routes
|
|
||||||
- **Detection**: Logs show route announcements but no tracking updates
|
|
||||||
- **Root Cause**: Missing synchronization points in `poll.go:420` area
|
|
||||||
|
|
||||||
3. **HA Failover Architecture Issues**: Routes removed when nodes go offline
|
|
||||||
- **Pattern**: `TestHASubnetRouterFailover` fails because approved routes disappear
|
|
||||||
- **Detection**: Routes available on online nodes but lost when nodes disconnect
|
|
||||||
- **Root Cause**: Conflating route approval with node connectivity
|
|
||||||
|
|
||||||
### Critical Test Environment Setup
|
|
||||||
|
|
||||||
**Pre-Test Cleanup**:
|
|
||||||
|
|
||||||
The test runner automatically handles cleanup:
|
|
||||||
- **Before test**: Removes only stale (stopped/exited) containers - does NOT affect running tests
|
|
||||||
- **After test**: Removes only containers belonging to the specific run ID
|
|
||||||
|
|
||||||
```bash
|
|
||||||
# Only clean old log directories if disk space is low
|
|
||||||
rm -rf control_logs/202507*
|
|
||||||
df -h # Verify sufficient disk space
|
|
||||||
|
|
||||||
# SAFE: Clean only stale/stopped containers (does not affect running tests)
|
|
||||||
# The test runner does this automatically via cleanupStaleTestContainers()
|
|
||||||
|
|
||||||
# ⚠️ DANGEROUS: Only use when NO tests are running
|
|
||||||
docker system prune -f
|
|
||||||
```
|
|
||||||
|
|
||||||
**Environment Verification**:
|
|
||||||
```bash
|
|
||||||
# Verify system readiness
|
|
||||||
go run ./cmd/hi doctor
|
|
||||||
|
|
||||||
# Check what tests are currently running (ALWAYS check before global cleanup)
|
|
||||||
docker ps --filter "name=headscale-test-suite" --format "{{.Names}}"
|
|
||||||
```
|
|
||||||
|
|
||||||
### Specific Test Categories and Known Issues
|
|
||||||
|
|
||||||
#### Route-Related Tests (Primary Focus)
|
|
||||||
```bash
|
|
||||||
# Core route functionality - these should work first
|
|
||||||
# Note: Generous timeouts are required for reliable execution
|
|
||||||
go run ./cmd/hi run "TestSubnetRouteACL" --timeout=1200s
|
|
||||||
go run ./cmd/hi run "TestAutoApproveMultiNetwork" --timeout=1800s
|
|
||||||
go run ./cmd/hi run "TestHASubnetRouterFailover" --timeout=1800s
|
|
||||||
```
|
|
||||||
|
|
||||||
**Common Route Test Patterns**:
|
|
||||||
- Tests validate route announcement, approval, and distribution workflows
|
|
||||||
- Route state changes are asynchronous - may need `EventuallyWithT` wrappers
|
|
||||||
- Route approval must respect ACL policies - test expectations encode security requirements
|
|
||||||
- HA tests verify route persistence during node connectivity changes
|
|
||||||
|
|
||||||
#### Authentication Tests (Infrastructure-Prone)
|
|
||||||
```bash
|
|
||||||
# These tests are more prone to infrastructure issues
|
|
||||||
# Require longer timeouts due to auth flow complexity
|
|
||||||
go run ./cmd/hi run "TestAuthKeyLogoutAndReloginSameUser" --timeout=1200s
|
|
||||||
go run ./cmd/hi run "TestAuthWebFlowLogoutAndRelogin" --timeout=1200s
|
|
||||||
go run ./cmd/hi run "TestOIDCExpireNodesBasedOnTokenExpiry" --timeout=1800s
|
|
||||||
```
|
|
||||||
|
|
||||||
**Common Auth Test Infrastructure Failures**:
|
|
||||||
- DNS resolution during logout operations
|
|
||||||
- Container creation timeouts
|
|
||||||
- HTTP/2 stream errors (often symptoms, not root cause)
|
|
||||||
|
|
||||||
### Security-Critical Debugging Rules
|
|
||||||
|
|
||||||
**❌ FORBIDDEN CHANGES (Security & Test Integrity)**:
|
|
||||||
1. **Never change expected test outputs** - Tests define correct behavior contracts
|
|
||||||
- Changing `require.Len(t, routes, 3)` to `require.Len(t, routes, 2)` because test fails
|
|
||||||
- Modifying expected status codes, node counts, or route counts
|
|
||||||
- Removing assertions that are "inconvenient"
|
|
||||||
- **Why forbidden**: Test expectations encode business requirements and security policies
|
|
||||||
|
|
||||||
2. **Never bypass security mechanisms** - Security must never be compromised for convenience
|
|
||||||
- Using `AnnouncedRoutes()` instead of `SubnetRoutes()` in production code
|
|
||||||
- Skipping authentication or authorization checks
|
|
||||||
- **Why forbidden**: Security bypasses create vulnerabilities in production
|
|
||||||
|
|
||||||
3. **Never reduce test coverage** - Tests prevent regressions
|
|
||||||
- Removing test cases or assertions
|
|
||||||
- Commenting out "problematic" test sections
|
|
||||||
- **Why forbidden**: Reduced coverage allows bugs to slip through
|
|
||||||
|
|
||||||
**✅ ALLOWED CHANGES (Timing & Observability)**:
|
|
||||||
1. **Fix timing issues with proper async patterns**
|
|
||||||
```go
|
|
||||||
// ✅ GOOD: Add EventuallyWithT for async operations
|
|
||||||
require.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Len(c, nodes, expectedCount) // Keep original expectation
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "nodes should reach expected count")
|
|
||||||
```
|
|
||||||
- **Why allowed**: Fixes race conditions without changing business logic
|
|
||||||
|
|
||||||
2. **Add MORE observability and debugging**
|
|
||||||
- Additional logging statements
|
|
||||||
- More detailed error messages
|
|
||||||
- Extra assertions that verify intermediate states
|
|
||||||
- **Why allowed**: Better observability helps debug without changing behavior
|
|
||||||
|
|
||||||
3. **Improve test documentation**
|
|
||||||
- Add godoc comments explaining test purpose and business logic
|
|
||||||
- Document timing requirements and async behavior
|
|
||||||
- **Why encouraged**: Helps future maintainers understand intent
|
|
||||||
|
|
||||||
### Advanced Debugging Workflows
|
|
||||||
|
|
||||||
#### Route Tracking Debug Flow
|
|
||||||
```bash
|
|
||||||
# Run test with detailed logging and proper timeout
|
|
||||||
go run ./cmd/hi run "TestSubnetRouteACL" --timeout=1200s > test_output.log 2>&1
|
|
||||||
|
|
||||||
# Check route approval process
|
|
||||||
grep -E "(auto-approval|ApproveRoutesWithPolicy|PolicyManager)" test_output.log
|
|
||||||
|
|
||||||
# Check route tracking
|
|
||||||
tail -50 control_logs/*/hs-*.stderr.log | grep -E "(announced|tracking|SetNodeRoutes)"
|
|
||||||
|
|
||||||
# Check for security violations
|
|
||||||
grep -E "(AnnouncedRoutes.*SetNodeRoutes|bypass.*approval)" test_output.log
|
|
||||||
```
|
|
||||||
|
|
||||||
#### HA Failover Debug Flow
|
|
||||||
```bash
|
|
||||||
# Test HA failover specifically with adequate timeout
|
|
||||||
go run ./cmd/hi run "TestHASubnetRouterFailover" --timeout=1800s
|
|
||||||
|
|
||||||
# Check route persistence during disconnect
|
|
||||||
grep -E "(Disconnect|NodeWentOffline|PrimaryRoutes)" control_logs/*/hs-*.stderr.log
|
|
||||||
|
|
||||||
# Verify routes don't disappear inappropriately
|
|
||||||
grep -E "(removing.*routes|SetNodeRoutes.*empty)" control_logs/*/hs-*.stderr.log
|
|
||||||
```
|
|
||||||
|
|
||||||
### Test Result Interpretation Guidelines
|
|
||||||
|
|
||||||
#### Success Patterns to Look For
|
|
||||||
- `"updating node routes for tracking"` in logs
|
|
||||||
- Routes appearing in `announcedRoutes` logs
|
|
||||||
- Proper `ApproveRoutesWithPolicy` calls for auto-approval
|
|
||||||
- Routes persisting through node connectivity changes (HA tests)
|
|
||||||
|
|
||||||
#### Failure Patterns to Investigate
|
|
||||||
- `SubnetRoutes()` returning empty when `AnnouncedRoutes()` has routes
|
|
||||||
- Routes disappearing when nodes go offline (HA architectural issue)
|
|
||||||
- Missing `EventuallyWithT` causing timing race conditions
|
|
||||||
- Security bypass attempts using wrong route methods
|
|
||||||
|
|
||||||
### Critical Testing Methodology
|
|
||||||
|
|
||||||
**Phase-Based Testing Approach**:
|
|
||||||
1. **Phase 1**: Core route tests (ACL, auto-approval, basic functionality)
|
|
||||||
2. **Phase 2**: HA and complex route scenarios
|
|
||||||
3. **Phase 3**: Auth tests (infrastructure-sensitive, test last)
|
|
||||||
|
|
||||||
**Per-Test Process**:
|
|
||||||
1. Clean environment before each test
|
|
||||||
2. Monitor logs for route tracking and approval messages
|
|
||||||
3. Check artifacts in `control_logs/` if test fails
|
|
||||||
4. Focus on actual error messages, not assumptions
|
|
||||||
5. Document results and patterns discovered
|
|
||||||
|
|
||||||
## Test Documentation and Code Quality Standards
|
|
||||||
|
|
||||||
### Adding Missing Test Documentation
|
|
||||||
When you understand a test's purpose through debugging, always add comprehensive godoc:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// TestSubnetRoutes validates the complete subnet route lifecycle including
|
|
||||||
// advertisement from clients, policy-based approval, and distribution to peers.
|
|
||||||
// This test ensures that route security policies are properly enforced and that
|
|
||||||
// only approved routes are distributed to the network.
|
|
||||||
//
|
|
||||||
// The test verifies:
|
|
||||||
// - Route announcements are received and tracked
|
|
||||||
// - ACL policies control route approval correctly
|
|
||||||
// - Only approved routes appear in peer network maps
|
|
||||||
// - Route state persists correctly in the database
|
|
||||||
func TestSubnetRoutes(t *testing.T) {
|
|
||||||
// Test implementation...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Why add documentation**: Future maintainers need to understand business logic and security requirements encoded in tests.
|
|
||||||
|
|
||||||
### Comment Guidelines - Focus on WHY, Not WHAT
|
|
||||||
|
|
||||||
```go
|
|
||||||
// ✅ GOOD: Explains reasoning and business logic
|
|
||||||
// Wait for route propagation because NodeStore updates are asynchronous
|
|
||||||
// and happen after poll requests complete processing
|
|
||||||
require.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
// Check that security policies are enforced...
|
|
||||||
}, timeout, interval, "route approval must respect ACL policies")
|
|
||||||
|
|
||||||
// ❌ BAD: Just describes what the code does
|
|
||||||
// Wait for routes
|
|
||||||
require.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
// Get routes and check length
|
|
||||||
}, timeout, interval, "checking routes")
|
|
||||||
```
|
|
||||||
|
|
||||||
**Why focus on WHY**: Helps maintainers understand architectural decisions and security requirements.
|
|
||||||
|
|
||||||
## EventuallyWithT Pattern for External Calls
|
|
||||||
|
|
||||||
### Overview
|
|
||||||
EventuallyWithT is a testing pattern used to handle eventual consistency in distributed systems. In Headscale integration tests, many operations are asynchronous - clients advertise routes, the server processes them, updates propagate through the network. EventuallyWithT allows tests to wait for these operations to complete while making assertions.
|
|
||||||
|
|
||||||
### External Calls That Must Be Wrapped
|
|
||||||
The following operations are **external calls** that interact with the headscale server or tailscale clients and MUST be wrapped in EventuallyWithT:
|
|
||||||
- `headscale.ListNodes()` - Queries server state
|
|
||||||
- `client.Status()` - Gets client network status
|
|
||||||
- `client.Curl()` - Makes HTTP requests through the network
|
|
||||||
- `client.Traceroute()` - Performs network diagnostics
|
|
||||||
- `client.Execute()` when running commands that query state
|
|
||||||
- Any operation that reads from the headscale server or tailscale client
|
|
||||||
|
|
||||||
### Five Key Rules for EventuallyWithT
|
|
||||||
|
|
||||||
1. **One External Call Per EventuallyWithT Block**
|
|
||||||
- Each EventuallyWithT should make ONE external call (e.g., ListNodes OR Status)
|
|
||||||
- Related assertions based on that single call can be grouped together
|
|
||||||
- Unrelated external calls must be in separate EventuallyWithT blocks
|
|
||||||
|
|
||||||
2. **Variable Scoping**
|
|
||||||
- Declare variables that need to be shared across EventuallyWithT blocks at function scope
|
|
||||||
- Use `=` for assignment inside EventuallyWithT, not `:=` (unless the variable is only used within that block)
|
|
||||||
- Variables declared with `:=` inside EventuallyWithT are not accessible outside
|
|
||||||
|
|
||||||
3. **No Nested EventuallyWithT**
|
|
||||||
- NEVER put an EventuallyWithT inside another EventuallyWithT
|
|
||||||
- This is a critical anti-pattern that must be avoided
|
|
||||||
|
|
||||||
4. **Use CollectT for Assertions**
|
|
||||||
- Inside EventuallyWithT, use `assert` methods with the CollectT parameter
|
|
||||||
- Helper functions called within EventuallyWithT must accept `*assert.CollectT`
|
|
||||||
|
|
||||||
5. **Descriptive Messages**
|
|
||||||
- Always provide a descriptive message as the last parameter
|
|
||||||
- Message should explain what condition is being waited for
|
|
||||||
|
|
||||||
### Correct Pattern Examples
|
|
||||||
|
|
||||||
```go
|
|
||||||
// CORRECT: Single external call with related assertions
|
|
||||||
var nodes []*v1.Node
|
|
||||||
var err error
|
|
||||||
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err = headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Len(c, nodes, 2)
|
|
||||||
// These assertions are all based on the ListNodes() call
|
|
||||||
requireNodeRouteCountWithCollect(c, nodes[0], 2, 2, 2)
|
|
||||||
requireNodeRouteCountWithCollect(c, nodes[1], 1, 1, 1)
|
|
||||||
}, 10*time.Second, 500*time.Millisecond, "nodes should have expected route counts")
|
|
||||||
|
|
||||||
// CORRECT: Separate EventuallyWithT for different external call
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
status, err := client.Status()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
// All these assertions are based on the single Status() call
|
|
||||||
for _, peerKey := range status.Peers() {
|
|
||||||
peerStatus := status.Peer[peerKey]
|
|
||||||
requirePeerSubnetRoutesWithCollect(c, peerStatus, expectedPrefixes)
|
|
||||||
}
|
|
||||||
}, 10*time.Second, 500*time.Millisecond, "client should see expected routes")
|
|
||||||
|
|
||||||
// CORRECT: Variable scoping for sharing between blocks
|
|
||||||
var routeNode *v1.Node
|
|
||||||
var nodeKey key.NodePublic
|
|
||||||
|
|
||||||
// First EventuallyWithT to get the node
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
|
|
||||||
for _, node := range nodes {
|
|
||||||
if node.GetName() == "router" {
|
|
||||||
routeNode = node
|
|
||||||
nodeKey, _ = key.ParseNodePublicUntyped(mem.S(node.GetNodeKey()))
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert.NotNil(c, routeNode, "should find router node")
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "router node should exist")
|
|
||||||
|
|
||||||
// Second EventuallyWithT using the nodeKey from first block
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
status, err := client.Status()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
|
|
||||||
peerStatus, ok := status.Peer[nodeKey]
|
|
||||||
assert.True(c, ok, "peer should exist in status")
|
|
||||||
requirePeerSubnetRoutesWithCollect(c, peerStatus, expectedPrefixes)
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "routes should be visible to client")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Incorrect Patterns to Avoid
|
|
||||||
|
|
||||||
```go
|
|
||||||
// INCORRECT: Multiple unrelated external calls in same EventuallyWithT
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
// First external call
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Len(c, nodes, 2)
|
|
||||||
|
|
||||||
// Second unrelated external call - WRONG!
|
|
||||||
status, err := client.Status()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.NotNil(c, status)
|
|
||||||
}, 10*time.Second, 500*time.Millisecond, "mixed operations")
|
|
||||||
|
|
||||||
// INCORRECT: Nested EventuallyWithT
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
|
|
||||||
// NEVER do this!
|
|
||||||
assert.EventuallyWithT(t, func(c2 *assert.CollectT) {
|
|
||||||
status, _ := client.Status()
|
|
||||||
assert.NotNil(c2, status)
|
|
||||||
}, 5*time.Second, 100*time.Millisecond, "nested")
|
|
||||||
}, 10*time.Second, 500*time.Millisecond, "outer")
|
|
||||||
|
|
||||||
// INCORRECT: Variable scoping error
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes() // This shadows outer 'nodes' variable
|
|
||||||
assert.NoError(c, err)
|
|
||||||
}, 10*time.Second, 500*time.Millisecond, "get nodes")
|
|
||||||
|
|
||||||
// This will fail - nodes is nil because := created a new variable inside the block
|
|
||||||
require.Len(t, nodes, 2) // COMPILATION ERROR or nil pointer
|
|
||||||
|
|
||||||
// INCORRECT: Not wrapping external calls
|
|
||||||
nodes, err := headscale.ListNodes() // External call not wrapped!
|
|
||||||
require.NoError(t, err)
|
|
||||||
```
|
|
||||||
|
|
||||||
### Helper Functions for EventuallyWithT
|
|
||||||
|
|
||||||
When creating helper functions for use within EventuallyWithT:
|
|
||||||
|
|
||||||
```go
|
|
||||||
// Helper function that accepts CollectT
|
|
||||||
func requireNodeRouteCountWithCollect(c *assert.CollectT, node *v1.Node, available, approved, primary int) {
|
|
||||||
assert.Len(c, node.GetAvailableRoutes(), available, "available routes for node %s", node.GetName())
|
|
||||||
assert.Len(c, node.GetApprovedRoutes(), approved, "approved routes for node %s", node.GetName())
|
|
||||||
assert.Len(c, node.GetPrimaryRoutes(), primary, "primary routes for node %s", node.GetName())
|
|
||||||
}
|
|
||||||
|
|
||||||
// Usage within EventuallyWithT
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
requireNodeRouteCountWithCollect(c, nodes[0], 2, 2, 2)
|
|
||||||
}, 10*time.Second, 500*time.Millisecond, "route counts should match expected")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Operations That Must NOT Be Wrapped
|
|
||||||
|
|
||||||
**CRITICAL**: The following operations are **blocking/mutating operations** that change state and MUST NOT be wrapped in EventuallyWithT:
|
|
||||||
- `tailscale set` commands (e.g., `--advertise-routes`, `--accept-routes`)
|
|
||||||
- `headscale.ApproveRoute()` - Approves routes on server
|
|
||||||
- `headscale.CreateUser()` - Creates users
|
|
||||||
- `headscale.CreatePreAuthKey()` - Creates authentication keys
|
|
||||||
- `headscale.RegisterNode()` - Registers new nodes
|
|
||||||
- Any `client.Execute()` that modifies configuration
|
|
||||||
- Any operation that creates, updates, or deletes resources
|
|
||||||
|
|
||||||
These operations:
|
|
||||||
1. Complete synchronously or fail immediately
|
|
||||||
2. Should not be retried automatically
|
|
||||||
3. Need explicit error handling with `require.NoError()`
|
|
||||||
|
|
||||||
### Correct Pattern for Blocking Operations
|
|
||||||
|
|
||||||
```go
|
|
||||||
// CORRECT: Blocking operation NOT wrapped
|
|
||||||
status := client.MustStatus()
|
|
||||||
command := []string{"tailscale", "set", "--advertise-routes=" + expectedRoutes[string(status.Self.ID)]}
|
|
||||||
_, _, err = client.Execute(command)
|
|
||||||
require.NoErrorf(t, err, "failed to advertise route: %s", err)
|
|
||||||
|
|
||||||
// Then wait for the result with EventuallyWithT
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Contains(c, nodes[0].GetAvailableRoutes(), expectedRoutes[string(status.Self.ID)])
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "route should be advertised")
|
|
||||||
|
|
||||||
// INCORRECT: Blocking operation wrapped (DON'T DO THIS)
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
_, _, err = client.Execute([]string{"tailscale", "set", "--advertise-routes=10.0.0.0/24"})
|
|
||||||
assert.NoError(c, err) // This might retry the command multiple times!
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "advertise routes")
|
|
||||||
```
|
|
||||||
|
|
||||||
### Assert vs Require Pattern
|
|
||||||
|
|
||||||
When working within EventuallyWithT blocks where you need to prevent panics:
|
|
||||||
|
|
||||||
```go
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
|
|
||||||
// For array bounds - use require with t to prevent panic
|
|
||||||
assert.Len(c, nodes, 6) // Test expectation
|
|
||||||
require.GreaterOrEqual(t, len(nodes), 3, "need at least 3 nodes to avoid panic")
|
|
||||||
|
|
||||||
// For nil pointer access - use require with t before dereferencing
|
|
||||||
assert.NotNil(c, srs1PeerStatus.PrimaryRoutes) // Test expectation
|
|
||||||
require.NotNil(t, srs1PeerStatus.PrimaryRoutes, "primary routes must be set to avoid panic")
|
|
||||||
assert.Contains(c,
|
|
||||||
srs1PeerStatus.PrimaryRoutes.AsSlice(),
|
|
||||||
pref,
|
|
||||||
)
|
|
||||||
}, 5*time.Second, 200*time.Millisecond, "checking route state")
|
|
||||||
```
|
|
||||||
|
|
||||||
**Key Principle**:
|
|
||||||
- Use `assert` with `c` (*assert.CollectT) for test expectations that can be retried
|
|
||||||
- Use `require` with `t` (*testing.T) for MUST conditions that prevent panics
|
|
||||||
- Within EventuallyWithT, both are available - choose based on whether failure would cause a panic
|
|
||||||
|
|
||||||
### Common Scenarios
|
|
||||||
|
|
||||||
1. **Waiting for route advertisement**:
|
|
||||||
```go
|
|
||||||
client.Execute([]string{"tailscale", "set", "--advertise-routes=10.0.0.0/24"})
|
|
||||||
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Contains(c, nodes[0].GetAvailableRoutes(), "10.0.0.0/24")
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "route should be advertised")
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Checking client sees routes**:
|
|
||||||
```go
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
status, err := client.Status()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
|
|
||||||
// Check all peers have expected routes
|
|
||||||
for _, peerKey := range status.Peers() {
|
|
||||||
peerStatus := status.Peer[peerKey]
|
|
||||||
assert.Contains(c, peerStatus.AllowedIPs, expectedPrefix)
|
|
||||||
}
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "all peers should see route")
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Sequential operations**:
|
|
||||||
```go
|
|
||||||
// First wait for node to appear
|
|
||||||
var nodeID uint64
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Len(c, nodes, 1)
|
|
||||||
nodeID = nodes[0].GetId()
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "node should register")
|
|
||||||
|
|
||||||
// Then perform operation
|
|
||||||
_, err := headscale.ApproveRoute(nodeID, "10.0.0.0/24")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// Then wait for result
|
|
||||||
assert.EventuallyWithT(t, func(c *assert.CollectT) {
|
|
||||||
nodes, err := headscale.ListNodes()
|
|
||||||
assert.NoError(c, err)
|
|
||||||
assert.Contains(c, nodes[0].GetApprovedRoutes(), "10.0.0.0/24")
|
|
||||||
}, 10*time.Second, 100*time.Millisecond, "route should be approved")
|
|
||||||
```
|
|
||||||
|
|
||||||
## Your Core Responsibilities
|
|
||||||
|
|
||||||
1. **Test Execution Strategy**: Execute integration tests with appropriate configurations, understanding when to use `--postgres` and timing requirements for different test categories. Follow phase-based testing approach prioritizing route tests.
|
|
||||||
- **Why this priority**: Route tests are less infrastructure-sensitive and validate core security logic
|
|
||||||
|
|
||||||
2. **Systematic Test Analysis**: When tests fail, systematically examine artifacts starting with Headscale server logs, then client logs, then protocol data. Focus on CODE ISSUES first (99% of cases), not infrastructure. Use real-world failure patterns to guide investigation.
|
|
||||||
- **Why this approach**: Most failures are logic bugs, not environment issues - efficient debugging saves time
|
|
||||||
|
|
||||||
3. **Timing & Synchronization Expertise**: Understand asynchronous Headscale operations, particularly route advertisements, NodeStore synchronization at `poll.go:420`, and policy propagation. Fix timing with `EventuallyWithT` while preserving original test expectations.
|
|
||||||
- **Why preserve expectations**: Test assertions encode business requirements and security policies
|
|
||||||
- **Key Pattern**: Apply the EventuallyWithT pattern correctly for all external calls as documented above
|
|
||||||
|
|
||||||
4. **Root Cause Analysis**: Distinguish between actual code regressions (route approval logic, HA failover architecture), timing issues requiring `EventuallyWithT` patterns, and genuine infrastructure problems (DNS, Docker, container issues).
|
|
||||||
- **Why this distinction matters**: Different problem types require completely different solution approaches
|
|
||||||
- **EventuallyWithT Issues**: Often manifest as flaky tests or immediate assertion failures after async operations
|
|
||||||
|
|
||||||
5. **Security-Aware Quality Validation**: Ensure tests properly validate end-to-end functionality with realistic timing expectations and proper error handling. Never suggest security bypasses or test expectation changes. Add comprehensive godoc when you understand test business logic.
|
|
||||||
- **Why security focus**: Integration tests are the last line of defense against security regressions
|
|
||||||
- **EventuallyWithT Usage**: Proper use prevents race conditions without weakening security assertions
|
|
||||||
|
|
||||||
6. **Concurrent Execution Awareness**: Respect run ID isolation and never interfere with other agents' test sessions. Each test run has a unique run ID - only clean up YOUR containers (by run ID label), never perform global cleanup while tests may be running.
|
|
||||||
- **Why this matters**: Multiple agents/users may run tests concurrently on the same Docker daemon
|
|
||||||
- **Key Rule**: NEVER use global container cleanup commands - the test runner handles cleanup automatically per run ID
|
|
||||||
|
|
||||||
**CRITICAL PRINCIPLE**: Test expectations are sacred contracts that define correct system behavior. When tests fail, fix the code to match the test, never change the test to match broken code. Only timing and observability improvements are allowed - business logic expectations are immutable.
|
|
||||||
|
|
||||||
**ISOLATION PRINCIPLE**: Each test run is isolated by its unique Run ID. Never interfere with other test sessions. The system handles cleanup automatically - manual global cleanup commands are forbidden when other tests may be running.
|
|
||||||
|
|
||||||
**EventuallyWithT PRINCIPLE**: Every external call to headscale server or tailscale client must be wrapped in EventuallyWithT. Follow the five key rules strictly: one external call per block, proper variable scoping, no nesting, use CollectT for assertions, and provide descriptive messages.
|
|
||||||
|
|
||||||
**Remember**: Test failures are usually code issues in Headscale that need to be fixed, not infrastructure problems to be ignored. Use the specific debugging workflows and failure patterns documented above to efficiently identify root causes. Infrastructure issues have very specific signatures - everything else is code-related.
|
|
||||||
@@ -17,7 +17,3 @@ LICENSE
|
|||||||
.vscode
|
.vscode
|
||||||
|
|
||||||
*.sock
|
*.sock
|
||||||
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
package.json
|
|
||||||
|
|||||||
@@ -1,16 +0,0 @@
|
|||||||
root = true
|
|
||||||
|
|
||||||
[*]
|
|
||||||
charset = utf-8
|
|
||||||
end_of_line = lf
|
|
||||||
indent_size = 2
|
|
||||||
indent_style = space
|
|
||||||
insert_final_newline = true
|
|
||||||
trim_trailing_whitespace = true
|
|
||||||
max_line_length = 120
|
|
||||||
|
|
||||||
[*.go]
|
|
||||||
indent_style = tab
|
|
||||||
|
|
||||||
[Makefile]
|
|
||||||
indent_style = tab
|
|
||||||
16
.github/CODEOWNERS
vendored
16
.github/CODEOWNERS
vendored
@@ -1,10 +1,10 @@
|
|||||||
* @juanfont @kradalby
|
* @juanfont @kradalby
|
||||||
|
|
||||||
*.md @ohdearaugustin @nblock
|
*.md @ohdearaugustin
|
||||||
*.yml @ohdearaugustin @nblock
|
*.yml @ohdearaugustin
|
||||||
*.yaml @ohdearaugustin @nblock
|
*.yaml @ohdearaugustin
|
||||||
Dockerfile* @ohdearaugustin @nblock
|
Dockerfile* @ohdearaugustin
|
||||||
.goreleaser.yaml @ohdearaugustin @nblock
|
.goreleaser.yaml @ohdearaugustin
|
||||||
/docs/ @ohdearaugustin @nblock
|
/docs/ @ohdearaugustin
|
||||||
/.github/workflows/ @ohdearaugustin @nblock
|
/.github/workflows/ @ohdearaugustin
|
||||||
/.github/renovate.json @ohdearaugustin @nblock
|
/.github/renovate.json @ohdearaugustin
|
||||||
|
|||||||
65
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
65
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
---
|
||||||
|
name: "Bug report"
|
||||||
|
about: "Create a bug report to help us improve"
|
||||||
|
title: ""
|
||||||
|
labels: ["bug"]
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
Before posting a bug report, discuss the behaviour you are expecting with the Discord community
|
||||||
|
to make sure that it is truly a bug.
|
||||||
|
The issue tracker is not the place to ask for support or how to set up Headscale.
|
||||||
|
|
||||||
|
Bug reports without the sufficient information will be closed.
|
||||||
|
|
||||||
|
Headscale is a multinational community across the globe. Our language is English.
|
||||||
|
All bug reports needs to be in English.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Bug description
|
||||||
|
|
||||||
|
<!-- A clear and concise description of what the bug is. Describe the expected bahavior
|
||||||
|
and how it is currently different. If you are unsure if it is a bug, consider discussing
|
||||||
|
it on our Discord server first. -->
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
<!-- Please add relevant information about your system. For example:
|
||||||
|
- Version of headscale used
|
||||||
|
- Version of tailscale client
|
||||||
|
- OS (e.g. Linux, Mac, Cygwin, WSL, etc.) and version
|
||||||
|
- Kernel version
|
||||||
|
- The relevant config parameters you used
|
||||||
|
- Log output
|
||||||
|
-->
|
||||||
|
|
||||||
|
- OS:
|
||||||
|
- Headscale version:
|
||||||
|
- Tailscale version:
|
||||||
|
|
||||||
|
<!--
|
||||||
|
We do not support running Headscale in a container nor behind a (reverse) proxy.
|
||||||
|
If either of these are true for your environment, ask the community in Discord
|
||||||
|
instead of filing a bug report.
|
||||||
|
-->
|
||||||
|
|
||||||
|
- [ ] Headscale is behind a (reverse) proxy
|
||||||
|
- [ ] Headscale runs in a container
|
||||||
|
|
||||||
|
## To Reproduce
|
||||||
|
|
||||||
|
<!-- Steps to reproduce the behavior. -->
|
||||||
|
|
||||||
|
## Logs and attachments
|
||||||
|
|
||||||
|
<!-- Please attach files with:
|
||||||
|
- Client netmap dump (see below)
|
||||||
|
- ACL configuration
|
||||||
|
- Headscale configuration
|
||||||
|
|
||||||
|
Dump the netmap of tailscale clients:
|
||||||
|
`tailscale debug netmap > DESCRIPTIVE_NAME.json`
|
||||||
|
|
||||||
|
Please provide information describing the netmap, which client, which headscale version etc.
|
||||||
|
-->
|
||||||
106
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
106
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -1,106 +0,0 @@
|
|||||||
name: 🐞 Bug
|
|
||||||
description: File a bug/issue
|
|
||||||
title: "[Bug] <title>"
|
|
||||||
labels: ["bug", "needs triage"]
|
|
||||||
body:
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Is this a support request?
|
|
||||||
description: This issue tracker is for bugs and feature requests only. If you need
|
|
||||||
help, please use ask in our Discord community
|
|
||||||
options:
|
|
||||||
- label: This is not a support request
|
|
||||||
required: true
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Is there an existing issue for this?
|
|
||||||
description: Please search to see if an issue already exists for the bug you
|
|
||||||
encountered.
|
|
||||||
options:
|
|
||||||
- label: I have searched the existing issues
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Current Behavior
|
|
||||||
description: A concise description of what you're experiencing.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Expected Behavior
|
|
||||||
description: A concise description of what you expected to happen.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Steps To Reproduce
|
|
||||||
description: Steps to reproduce the behavior.
|
|
||||||
placeholder: |
|
|
||||||
1. In this environment...
|
|
||||||
1. With this config...
|
|
||||||
1. Run '...'
|
|
||||||
1. See error...
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Environment
|
|
||||||
description: |
|
|
||||||
Please provide information about your environment.
|
|
||||||
If you are using a container, always provide the headscale version and not only the Docker image version.
|
|
||||||
Please do not put "latest".
|
|
||||||
|
|
||||||
Describe your "headscale network". Is there a lot of nodes, are the nodes all interconnected, are some subnet routers?
|
|
||||||
|
|
||||||
If you are experiencing a problem during an upgrade, please provide the versions of the old and new versions of Headscale and Tailscale.
|
|
||||||
|
|
||||||
examples:
|
|
||||||
- **OS**: Ubuntu 24.04
|
|
||||||
- **Headscale version**: 0.24.3
|
|
||||||
- **Tailscale version**: 1.80.0
|
|
||||||
- **Number of nodes**: 20
|
|
||||||
value: |
|
|
||||||
- OS:
|
|
||||||
- Headscale version:
|
|
||||||
- Tailscale version:
|
|
||||||
render: markdown
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Runtime environment
|
|
||||||
options:
|
|
||||||
- label: Headscale is behind a (reverse) proxy
|
|
||||||
required: false
|
|
||||||
- label: Headscale runs in a container
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Debug information
|
|
||||||
description: |
|
|
||||||
Please have a look at our [Debugging and troubleshooting
|
|
||||||
guide](https://headscale.net/development/ref/debug/) to learn about
|
|
||||||
common debugging techniques.
|
|
||||||
|
|
||||||
Links? References? Anything that will give us more context about the issue you are encountering.
|
|
||||||
If **any** of these are omitted we will likely close your issue, do **not** ignore them.
|
|
||||||
|
|
||||||
- Client netmap dump (see below)
|
|
||||||
- Policy configuration
|
|
||||||
- Headscale configuration
|
|
||||||
- Headscale log (with `trace` enabled)
|
|
||||||
|
|
||||||
Dump the netmap of tailscale clients:
|
|
||||||
`tailscale debug netmap > DESCRIPTIVE_NAME.json`
|
|
||||||
|
|
||||||
Dump the status of tailscale clients:
|
|
||||||
`tailscale status --json > DESCRIPTIVE_NAME.json`
|
|
||||||
|
|
||||||
Get the logs of a Tailscale client that is not working as expected.
|
|
||||||
`tailscale debug daemon-logs`
|
|
||||||
|
|
||||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
|
||||||
**Ensure** you use formatting for files you attach.
|
|
||||||
Do **not** paste in long files.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
8
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -3,9 +3,9 @@ blank_issues_enabled: false
|
|||||||
|
|
||||||
# Contact links
|
# Contact links
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: "headscale Discord community"
|
|
||||||
url: "https://discord.gg/c84AZQhmpx"
|
|
||||||
about: "Please ask and answer questions about usage of headscale here."
|
|
||||||
- name: "headscale usage documentation"
|
- name: "headscale usage documentation"
|
||||||
url: "https://headscale.net/"
|
url: "https://github.com/juanfont/headscale/blob/main/docs"
|
||||||
about: "Find documentation about how to configure and run headscale."
|
about: "Find documentation about how to configure and run headscale."
|
||||||
|
- name: "headscale Discord community"
|
||||||
|
url: "https://discord.gg/xGj2TuqyxY"
|
||||||
|
about: "Please ask and answer questions about usage of headscale here."
|
||||||
|
|||||||
26
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
26
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
---
|
||||||
|
name: "Feature request"
|
||||||
|
about: "Suggest an idea for headscale"
|
||||||
|
title: ""
|
||||||
|
labels: ["enhancement"]
|
||||||
|
assignees: ""
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
We typically have a clear roadmap for what we want to improve and reserve the right
|
||||||
|
to close feature requests that does not fit in the roadmap, or fit with the scope
|
||||||
|
of the project, or we actually want to implement ourselves.
|
||||||
|
|
||||||
|
Headscale is a multinational community across the globe. Our language is English.
|
||||||
|
All bug reports needs to be in English.
|
||||||
|
-->
|
||||||
|
|
||||||
|
## Why
|
||||||
|
|
||||||
|
<!-- Include the reason, why you would need the feature. E.g. what problem
|
||||||
|
does it solve? Or which workflow is currently frustrating and will be improved by
|
||||||
|
this? -->
|
||||||
|
|
||||||
|
## Description
|
||||||
|
|
||||||
|
<!-- A clear and precise description of what new or changed feature you want. -->
|
||||||
36
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
36
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
@@ -1,36 +0,0 @@
|
|||||||
name: 🚀 Feature Request
|
|
||||||
description: Suggest an idea for Headscale
|
|
||||||
title: "[Feature] <title>"
|
|
||||||
labels: [enhancement]
|
|
||||||
body:
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Use case
|
|
||||||
description: Please describe the use case for this feature.
|
|
||||||
placeholder: |
|
|
||||||
<!-- Include the reason, why you would need the feature. E.g. what problem
|
|
||||||
does it solve? Or which workflow is currently frustrating and will be improved by
|
|
||||||
this? -->
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Description
|
|
||||||
description: A clear and precise description of what new or changed feature you want.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: checkboxes
|
|
||||||
attributes:
|
|
||||||
label: Contribution
|
|
||||||
description: Are you willing to contribute to the implementation of this feature?
|
|
||||||
options:
|
|
||||||
- label: I can write the design doc for this feature
|
|
||||||
required: false
|
|
||||||
- label: I can contribute this feature
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: How can it be implemented?
|
|
||||||
description: Free text for your ideas on how this feature could be implemented.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
80
.github/label-response/needs-more-info.md
vendored
80
.github/label-response/needs-more-info.md
vendored
@@ -1,80 +0,0 @@
|
|||||||
Thank you for taking the time to report this issue.
|
|
||||||
|
|
||||||
To help us investigate and resolve this, we need more information. Please provide the following:
|
|
||||||
|
|
||||||
> [!TIP]
|
|
||||||
> Most issues turn out to be configuration errors rather than bugs. We encourage you to discuss your problem in our [Discord community](https://discord.gg/c84AZQhmpx) **before** opening an issue. The community can often help identify misconfigurations quickly, saving everyone time.
|
|
||||||
|
|
||||||
## Required Information
|
|
||||||
|
|
||||||
### Environment Details
|
|
||||||
|
|
||||||
- **Headscale version**: (run `headscale version`)
|
|
||||||
- **Tailscale client version**: (run `tailscale version`)
|
|
||||||
- **Operating System**: (e.g., Ubuntu 24.04, macOS 14, Windows 11)
|
|
||||||
- **Deployment method**: (binary, Docker, Kubernetes, etc.)
|
|
||||||
- **Reverse proxy**: (if applicable: nginx, Traefik, Caddy, etc. - include configuration)
|
|
||||||
|
|
||||||
### Debug Information
|
|
||||||
|
|
||||||
Please follow our [Debugging and Troubleshooting Guide](https://headscale.net/stable/ref/debug/) and provide:
|
|
||||||
|
|
||||||
1. **Client netmap dump** (from affected Tailscale client):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tailscale debug netmap > netmap.json
|
|
||||||
```
|
|
||||||
|
|
||||||
2. **Client status dump** (from affected Tailscale client):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tailscale status --json > status.json
|
|
||||||
```
|
|
||||||
|
|
||||||
3. **Tailscale client logs** (if experiencing client issues):
|
|
||||||
|
|
||||||
```bash
|
|
||||||
tailscale debug daemon-logs
|
|
||||||
```
|
|
||||||
|
|
||||||
> [!IMPORTANT]
|
|
||||||
> We need logs from **multiple nodes** to understand the full picture:
|
|
||||||
>
|
|
||||||
> - The node(s) initiating connections
|
|
||||||
> - The node(s) being connected to
|
|
||||||
>
|
|
||||||
> Without logs from both sides, we cannot diagnose connectivity issues.
|
|
||||||
|
|
||||||
4. **Headscale server logs** with `log.level: trace` enabled
|
|
||||||
|
|
||||||
5. **Headscale configuration** (with sensitive values redacted - see rules below)
|
|
||||||
|
|
||||||
6. **ACL/Policy configuration** (if using ACLs)
|
|
||||||
|
|
||||||
7. **Proxy/Docker configuration** (if applicable - nginx.conf, docker-compose.yml, Traefik config, etc.)
|
|
||||||
|
|
||||||
## Formatting Requirements
|
|
||||||
|
|
||||||
- **Attach long files** - Do not paste large logs or configurations inline. Use GitHub file attachments or GitHub Gists.
|
|
||||||
- **Use proper Markdown** - Format code blocks, logs, and configurations with appropriate syntax highlighting.
|
|
||||||
- **Structure your response** - Use the headings above to organize your information clearly.
|
|
||||||
|
|
||||||
## Redaction Rules
|
|
||||||
|
|
||||||
> [!CAUTION]
|
|
||||||
> **Replace, do not remove.** Removing information makes debugging impossible.
|
|
||||||
|
|
||||||
When redacting sensitive information:
|
|
||||||
|
|
||||||
- ✅ **Replace consistently** - If you change `alice@company.com` to `user1@example.com`, use `user1@example.com` everywhere (logs, config, policy, etc.)
|
|
||||||
- ✅ **Use meaningful placeholders** - `user1@example.com`, `bob@example.com`, `my-secret-key` are acceptable
|
|
||||||
- ❌ **Never remove information** - Gaps in data prevent us from correlating events across logs
|
|
||||||
- ❌ **Never redact IP addresses** - We need the actual IPs to trace network paths and identify issues
|
|
||||||
|
|
||||||
**If redaction rules are not followed, we will be unable to debug the issue and will have to close it.**
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Note:** This issue will be automatically closed in 3 days if no additional information is provided. Once you reply with the requested information, the `needs-more-info` label will be removed automatically.
|
|
||||||
|
|
||||||
If you need help gathering this information, please visit our [Discord community](https://discord.gg/c84AZQhmpx).
|
|
||||||
15
.github/label-response/support-request.md
vendored
15
.github/label-response/support-request.md
vendored
@@ -1,15 +0,0 @@
|
|||||||
Thank you for reaching out.
|
|
||||||
|
|
||||||
This issue tracker is used for **bug reports and feature requests** only. Your question appears to be a support or configuration question rather than a bug report.
|
|
||||||
|
|
||||||
For help with setup, configuration, or general questions, please visit our [Discord community](https://discord.gg/c84AZQhmpx) where the community and maintainers can assist you in real-time.
|
|
||||||
|
|
||||||
**Before posting in Discord, please check:**
|
|
||||||
|
|
||||||
- [Documentation](https://headscale.net/)
|
|
||||||
- [FAQ](https://headscale.net/stable/faq/)
|
|
||||||
- [Debugging and Troubleshooting Guide](https://headscale.net/stable/ref/debug/)
|
|
||||||
|
|
||||||
If after troubleshooting you determine this is actually a bug, please open a new issue with the required debug information from the troubleshooting guide.
|
|
||||||
|
|
||||||
This issue has been automatically closed.
|
|
||||||
2
.github/pull_request_template.md
vendored
2
.github/pull_request_template.md
vendored
@@ -12,7 +12,7 @@ If you find mistakes in the documentation, please submit a fix to the documentat
|
|||||||
|
|
||||||
<!-- Please tick if the following things apply. You… -->
|
<!-- Please tick if the following things apply. You… -->
|
||||||
|
|
||||||
- [ ] have read the [CONTRIBUTING.md](./CONTRIBUTING.md) file
|
- [ ] read the [CONTRIBUTING guidelines](README.md#contributing)
|
||||||
- [ ] raised a GitHub issue or discussed it on the projects chat beforehand
|
- [ ] raised a GitHub issue or discussed it on the projects chat beforehand
|
||||||
- [ ] added unit tests
|
- [ ] added unit tests
|
||||||
- [ ] added integration tests
|
- [ ] added integration tests
|
||||||
|
|||||||
73
.github/workflows/build.yml
vendored
73
.github/workflows/build.yml
vendored
@@ -5,42 +5,42 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
pull_request:
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build-nix:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions: write-all
|
permissions: write-all
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
uses: tj-actions/changed-files@v34
|
||||||
with:
|
with:
|
||||||
filters: |
|
files: |
|
||||||
files:
|
*.nix
|
||||||
- '*.nix'
|
go.*
|
||||||
- 'go.*'
|
**/*.go
|
||||||
- '**/*.go'
|
integration_test/
|
||||||
- 'integration_test/'
|
config-example.yaml
|
||||||
- 'config-example.yaml'
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Run nix build
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
|
||||||
|
- name: Run build
|
||||||
id: build
|
id: build
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: |
|
run: |
|
||||||
nix build |& tee build-result
|
nix build |& tee build-result
|
||||||
BUILD_STATUS="${PIPESTATUS[0]}"
|
BUILD_STATUS="${PIPESTATUS[0]}"
|
||||||
@@ -54,7 +54,7 @@ jobs:
|
|||||||
exit $BUILD_STATUS
|
exit $BUILD_STATUS
|
||||||
|
|
||||||
- name: Nix gosum diverging
|
- name: Nix gosum diverging
|
||||||
uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0
|
uses: actions/github-script@v6
|
||||||
if: failure() && steps.build.outcome == 'failure'
|
if: failure() && steps.build.outcome == 'failure'
|
||||||
with:
|
with:
|
||||||
github-token: ${{secrets.GITHUB_TOKEN}}
|
github-token: ${{secrets.GITHUB_TOKEN}}
|
||||||
@@ -66,35 +66,8 @@ jobs:
|
|||||||
body: 'Nix build failed with wrong gosum, please update "vendorSha256" (${{ steps.build.outputs.OLD_HASH }}) for the "headscale" package in flake.nix with the new SHA: ${{ steps.build.outputs.NEW_HASH }}'
|
body: 'Nix build failed with wrong gosum, please update "vendorSha256" (${{ steps.build.outputs.OLD_HASH }}) for the "headscale" package in flake.nix with the new SHA: ${{ steps.build.outputs.NEW_HASH }}'
|
||||||
})
|
})
|
||||||
|
|
||||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
- uses: actions/upload-artifact@v3
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
with:
|
||||||
name: headscale-linux
|
name: headscale-linux
|
||||||
path: result/bin/headscale
|
path: result/bin/headscale
|
||||||
build-cross:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
strategy:
|
|
||||||
matrix:
|
|
||||||
env:
|
|
||||||
- "GOARCH=arm64 GOOS=linux"
|
|
||||||
- "GOARCH=amd64 GOOS=linux"
|
|
||||||
- "GOARCH=arm64 GOOS=darwin"
|
|
||||||
- "GOARCH=amd64 GOOS=darwin"
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Run go cross compile
|
|
||||||
env:
|
|
||||||
CGO_ENABLED: 0
|
|
||||||
run: env ${{ matrix.env }} nix develop --command -- go build -o "headscale"
|
|
||||||
./cmd/headscale
|
|
||||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
with:
|
|
||||||
name: "headscale-${{ matrix.env }}"
|
|
||||||
path: "headscale"
|
|
||||||
|
|||||||
55
.github/workflows/check-generated.yml
vendored
55
.github/workflows/check-generated.yml
vendored
@@ -1,55 +0,0 @@
|
|||||||
name: Check Generated Files
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-generated:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
files:
|
|
||||||
- '*.nix'
|
|
||||||
- 'go.*'
|
|
||||||
- '**/*.go'
|
|
||||||
- '**/*.proto'
|
|
||||||
- 'buf.gen.yaml'
|
|
||||||
- 'tools/**'
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Run make generate
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: nix develop --command -- make generate
|
|
||||||
|
|
||||||
- name: Check for uncommitted changes
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
if ! git diff --exit-code; then
|
|
||||||
echo "❌ Generated files are not up to date!"
|
|
||||||
echo "Please run 'make generate' and commit the changes."
|
|
||||||
exit 1
|
|
||||||
else
|
|
||||||
echo "✅ All generated files are up to date."
|
|
||||||
fi
|
|
||||||
45
.github/workflows/check-tests.yaml
vendored
45
.github/workflows/check-tests.yaml
vendored
@@ -1,45 +0,0 @@
|
|||||||
name: Check integration tests workflow
|
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
check-tests:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
files:
|
|
||||||
- '*.nix'
|
|
||||||
- 'go.*'
|
|
||||||
- '**/*.go'
|
|
||||||
- 'integration_test/'
|
|
||||||
- 'config-example.yaml'
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Generate and check integration tests
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
nix develop --command bash -c "cd .github/workflows && go generate"
|
|
||||||
git diff --exit-code .github/workflows/test-integration.yaml
|
|
||||||
|
|
||||||
- name: Show missing tests
|
|
||||||
if: failure()
|
|
||||||
run: |
|
|
||||||
git diff .github/workflows/test-integration.yaml
|
|
||||||
35
.github/workflows/contributors.yml
vendored
Normal file
35
.github/workflows/contributors.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
name: Contributors
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
jobs:
|
||||||
|
add-contributors:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Delete upstream contributor branch
|
||||||
|
# Allow continue on failure to account for when the
|
||||||
|
# upstream branch is deleted or does not exist.
|
||||||
|
continue-on-error: true
|
||||||
|
run: git push origin --delete update-contributors
|
||||||
|
- name: Create up-to-date contributors branch
|
||||||
|
run: git checkout -B update-contributors
|
||||||
|
- name: Push empty contributors branch
|
||||||
|
run: git push origin update-contributors
|
||||||
|
- name: Switch back to main
|
||||||
|
run: git checkout main
|
||||||
|
- uses: BobAnkh/add-contributors@v0.2.2
|
||||||
|
with:
|
||||||
|
CONTRIBUTOR: "## Contributors"
|
||||||
|
COLUMN_PER_ROW: "6"
|
||||||
|
ACCESS_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||||
|
IMG_WIDTH: "100"
|
||||||
|
FONT_SIZE: "14"
|
||||||
|
PATH: "/README.md"
|
||||||
|
COMMIT_MESSAGE: "docs(README): update contributors"
|
||||||
|
AVATAR_SHAPE: "round"
|
||||||
|
BRANCH: "update-contributors"
|
||||||
|
PULL_REQUEST: "main"
|
||||||
51
.github/workflows/docs-deploy.yml
vendored
51
.github/workflows/docs-deploy.yml
vendored
@@ -1,51 +0,0 @@
|
|||||||
name: Deploy docs
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
# Main branch for development docs
|
|
||||||
- main
|
|
||||||
|
|
||||||
# Doc maintenance branches
|
|
||||||
- doc/[0-9]+.[0-9]+.[0-9]+
|
|
||||||
tags:
|
|
||||||
# Stable release tags
|
|
||||||
- v[0-9]+.[0-9]+.[0-9]+
|
|
||||||
paths:
|
|
||||||
- "docs/**"
|
|
||||||
- "mkdocs.yml"
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
deploy:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Install python
|
|
||||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
- name: Setup cache
|
|
||||||
uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v5.0.0
|
|
||||||
with:
|
|
||||||
key: ${{ github.ref }}
|
|
||||||
path: .cache
|
|
||||||
- name: Setup dependencies
|
|
||||||
run: pip install -r docs/requirements.txt
|
|
||||||
- name: Configure git
|
|
||||||
run: |
|
|
||||||
git config user.name github-actions
|
|
||||||
git config user.email github-actions@github.com
|
|
||||||
- name: Deploy development docs
|
|
||||||
if: github.ref == 'refs/heads/main'
|
|
||||||
run: mike deploy --push development unstable
|
|
||||||
- name: Deploy stable docs from doc branches
|
|
||||||
if: startsWith(github.ref, 'refs/heads/doc/')
|
|
||||||
run: mike deploy --push ${GITHUB_REF_NAME##*/}
|
|
||||||
- name: Deploy stable docs from tag
|
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
|
||||||
# This assumes that only newer tags are pushed
|
|
||||||
run: mike deploy --push --update-aliases ${GITHUB_REF_NAME#v} stable latest
|
|
||||||
27
.github/workflows/docs-test.yml
vendored
27
.github/workflows/docs-test.yml
vendored
@@ -1,27 +0,0 @@
|
|||||||
name: Test documentation build
|
|
||||||
|
|
||||||
on: [pull_request]
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
- name: Install python
|
|
||||||
uses: actions/setup-python@83679a892e2d95755f2dac6acb0bfd1e9ac5d548 # v6.1.0
|
|
||||||
with:
|
|
||||||
python-version: 3.x
|
|
||||||
- name: Setup cache
|
|
||||||
uses: actions/cache@a7833574556fa59680c1b7cb190c1735db73ebf0 # v5.0.0
|
|
||||||
with:
|
|
||||||
key: ${{ github.ref }}
|
|
||||||
path: .cache
|
|
||||||
- name: Setup dependencies
|
|
||||||
run: pip install -r docs/requirements.txt
|
|
||||||
- name: Build docs
|
|
||||||
run: mkdocs build --strict
|
|
||||||
45
.github/workflows/docs.yml
vendored
Normal file
45
.github/workflows/docs.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: Build documentation
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- main
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Install python
|
||||||
|
uses: actions/setup-python@v4
|
||||||
|
with:
|
||||||
|
python-version: 3.x
|
||||||
|
- name: Setup cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
key: ${{ github.ref }}
|
||||||
|
path: .cache
|
||||||
|
- name: Setup dependencies
|
||||||
|
run: pip install -r docs/requirements.txt
|
||||||
|
- name: Build docs
|
||||||
|
run: mkdocs build --strict
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v1
|
||||||
|
with:
|
||||||
|
path: ./site
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: build
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v1
|
||||||
143
.github/workflows/gh-action-integration-generator.go
vendored
143
.github/workflows/gh-action-integration-generator.go
vendored
@@ -1,143 +0,0 @@
|
|||||||
package main
|
|
||||||
|
|
||||||
//go:generate go run ./gh-action-integration-generator.go
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os/exec"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// testsToSplit defines tests that should be split into multiple CI jobs.
|
|
||||||
// Key is the test function name, value is a list of subtest prefixes.
|
|
||||||
// Each prefix becomes a separate CI job as "TestName/prefix".
|
|
||||||
//
|
|
||||||
// Example: TestAutoApproveMultiNetwork has subtests like:
|
|
||||||
// - TestAutoApproveMultiNetwork/authkey-tag-advertiseduringup-false-pol-database
|
|
||||||
// - TestAutoApproveMultiNetwork/webauth-user-advertiseduringup-true-pol-file
|
|
||||||
//
|
|
||||||
// Splitting by approver type (tag, user, group) creates 6 CI jobs with 4 tests each:
|
|
||||||
// - TestAutoApproveMultiNetwork/authkey-tag.* (4 tests)
|
|
||||||
// - TestAutoApproveMultiNetwork/authkey-user.* (4 tests)
|
|
||||||
// - TestAutoApproveMultiNetwork/authkey-group.* (4 tests)
|
|
||||||
// - TestAutoApproveMultiNetwork/webauth-tag.* (4 tests)
|
|
||||||
// - TestAutoApproveMultiNetwork/webauth-user.* (4 tests)
|
|
||||||
// - TestAutoApproveMultiNetwork/webauth-group.* (4 tests)
|
|
||||||
//
|
|
||||||
// This reduces load per CI job (4 tests instead of 12) to avoid infrastructure
|
|
||||||
// flakiness when running many sequential Docker-based integration tests.
|
|
||||||
var testsToSplit = map[string][]string{
|
|
||||||
"TestAutoApproveMultiNetwork": {
|
|
||||||
"authkey-tag",
|
|
||||||
"authkey-user",
|
|
||||||
"authkey-group",
|
|
||||||
"webauth-tag",
|
|
||||||
"webauth-user",
|
|
||||||
"webauth-group",
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// expandTests takes a list of test names and expands any that need splitting
|
|
||||||
// into multiple subtest patterns.
|
|
||||||
func expandTests(tests []string) []string {
|
|
||||||
var expanded []string
|
|
||||||
for _, test := range tests {
|
|
||||||
if prefixes, ok := testsToSplit[test]; ok {
|
|
||||||
// This test should be split into multiple jobs.
|
|
||||||
// We append ".*" to each prefix because the CI runner wraps patterns
|
|
||||||
// with ^...$ anchors. Without ".*", a pattern like "authkey$" wouldn't
|
|
||||||
// match "authkey-tag-advertiseduringup-false-pol-database".
|
|
||||||
for _, prefix := range prefixes {
|
|
||||||
expanded = append(expanded, fmt.Sprintf("%s/%s.*", test, prefix))
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
expanded = append(expanded, test)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return expanded
|
|
||||||
}
|
|
||||||
|
|
||||||
func findTests() []string {
|
|
||||||
rgBin, err := exec.LookPath("rg")
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to find rg (ripgrep) binary")
|
|
||||||
}
|
|
||||||
|
|
||||||
args := []string{
|
|
||||||
"--regexp", "func (Test.+)\\(.*",
|
|
||||||
"../../integration/",
|
|
||||||
"--replace", "$1",
|
|
||||||
"--sort", "path",
|
|
||||||
"--no-line-number",
|
|
||||||
"--no-filename",
|
|
||||||
"--no-heading",
|
|
||||||
}
|
|
||||||
|
|
||||||
cmd := exec.Command(rgBin, args...)
|
|
||||||
var out bytes.Buffer
|
|
||||||
cmd.Stdout = &out
|
|
||||||
err = cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
log.Fatalf("failed to run command: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
tests := strings.Split(strings.TrimSpace(out.String()), "\n")
|
|
||||||
return tests
|
|
||||||
}
|
|
||||||
|
|
||||||
func updateYAML(tests []string, jobName string, testPath string) {
|
|
||||||
testsForYq := fmt.Sprintf("[%s]", strings.Join(tests, ", "))
|
|
||||||
|
|
||||||
yqCommand := fmt.Sprintf(
|
|
||||||
"yq eval '.jobs.%s.strategy.matrix.test = %s' %s -i",
|
|
||||||
jobName,
|
|
||||||
testsForYq,
|
|
||||||
testPath,
|
|
||||||
)
|
|
||||||
cmd := exec.Command("bash", "-c", yqCommand)
|
|
||||||
|
|
||||||
var stdout bytes.Buffer
|
|
||||||
var stderr bytes.Buffer
|
|
||||||
cmd.Stdout = &stdout
|
|
||||||
cmd.Stderr = &stderr
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("stdout: %s", stdout.String())
|
|
||||||
log.Printf("stderr: %s", stderr.String())
|
|
||||||
log.Fatalf("failed to run yq command: %s", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
fmt.Printf("YAML file (%s) job %s updated successfully\n", testPath, jobName)
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
tests := findTests()
|
|
||||||
|
|
||||||
// Expand tests that should be split into multiple jobs
|
|
||||||
expandedTests := expandTests(tests)
|
|
||||||
|
|
||||||
quotedTests := make([]string, len(expandedTests))
|
|
||||||
for i, test := range expandedTests {
|
|
||||||
quotedTests[i] = fmt.Sprintf("\"%s\"", test)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define selected tests for PostgreSQL
|
|
||||||
postgresTestNames := []string{
|
|
||||||
"TestACLAllowUserDst",
|
|
||||||
"TestPingAllByIP",
|
|
||||||
"TestEphemeral2006DeletedTooQuickly",
|
|
||||||
"TestPingAllByIPManyUpDown",
|
|
||||||
"TestSubnetRouterMultiNetwork",
|
|
||||||
}
|
|
||||||
|
|
||||||
quotedPostgresTests := make([]string, len(postgresTestNames))
|
|
||||||
for i, test := range postgresTestNames {
|
|
||||||
quotedPostgresTests[i] = fmt.Sprintf("\"%s\"", test)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update both SQLite and PostgreSQL job matrices
|
|
||||||
updateYAML(quotedTests, "sqlite", "./test-integration.yaml")
|
|
||||||
updateYAML(quotedPostgresTests, "postgres", "./test-integration.yaml")
|
|
||||||
}
|
|
||||||
6
.github/workflows/gh-actions-updater.yaml
vendored
6
.github/workflows/gh-actions-updater.yaml
vendored
@@ -1,5 +1,6 @@
|
|||||||
name: GitHub Actions Version Updater
|
name: GitHub Actions Version Updater
|
||||||
|
|
||||||
|
# Controls when the action will run.
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
# Automatically run on every Sunday
|
# Automatically run on every Sunday
|
||||||
@@ -7,17 +8,16 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
if: github.repository == 'juanfont/headscale'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
# [Required] Access token with `workflow` scope.
|
# [Required] Access token with `workflow` scope.
|
||||||
token: ${{ secrets.WORKFLOW_SECRET }}
|
token: ${{ secrets.WORKFLOW_SECRET }}
|
||||||
|
|
||||||
- name: Run GitHub Actions Version Updater
|
- name: Run GitHub Actions Version Updater
|
||||||
uses: saadmk11/github-actions-version-updater@d8781caf11d11168579c8e5e94f62b068038f442 # v0.9.0
|
uses: saadmk11/github-actions-version-updater@v0.7.1
|
||||||
with:
|
with:
|
||||||
# [Required] Access token with `workflow` scope.
|
# [Required] Access token with `workflow` scope.
|
||||||
token: ${{ secrets.WORKFLOW_SECRET }}
|
token: ${{ secrets.WORKFLOW_SECRET }}
|
||||||
|
|||||||
130
.github/workflows/integration-test-template.yml
vendored
130
.github/workflows/integration-test-template.yml
vendored
@@ -1,130 +0,0 @@
|
|||||||
name: Integration Test Template
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_call:
|
|
||||||
inputs:
|
|
||||||
test:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
postgres_flag:
|
|
||||||
required: false
|
|
||||||
type: string
|
|
||||||
default: ""
|
|
||||||
database_name:
|
|
||||||
required: true
|
|
||||||
type: string
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
env:
|
|
||||||
# Github does not allow us to access secrets in pull requests,
|
|
||||||
# so this env var is used to check if we have the secret or not.
|
|
||||||
# If we have the secrets, meaning we are running on push in a fork,
|
|
||||||
# there might be secrets available for more debugging.
|
|
||||||
# If TS_OAUTH_CLIENT_ID and TS_OAUTH_SECRET is set, then the job
|
|
||||||
# will join a debug tailscale network, set up SSH and a tmux session.
|
|
||||||
# The SSH will be configured to use the SSH key of the Github user
|
|
||||||
# that triggered the build.
|
|
||||||
HAS_TAILSCALE_SECRET: ${{ secrets.TS_OAUTH_CLIENT_ID }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
- name: Tailscale
|
|
||||||
if: ${{ env.HAS_TAILSCALE_SECRET }}
|
|
||||||
uses: tailscale/github-action@a392da0a182bba0e9613b6243ebd69529b1878aa # v4.1.0
|
|
||||||
with:
|
|
||||||
oauth-client-id: ${{ secrets.TS_OAUTH_CLIENT_ID }}
|
|
||||||
oauth-secret: ${{ secrets.TS_OAUTH_SECRET }}
|
|
||||||
tags: tag:gh
|
|
||||||
- name: Setup SSH server for Actor
|
|
||||||
if: ${{ env.HAS_TAILSCALE_SECRET }}
|
|
||||||
uses: alexellis/setup-sshd-actor@master
|
|
||||||
- name: Download headscale image
|
|
||||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
||||||
with:
|
|
||||||
name: headscale-image
|
|
||||||
path: /tmp/artifacts
|
|
||||||
- name: Download tailscale HEAD image
|
|
||||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
||||||
with:
|
|
||||||
name: tailscale-head-image
|
|
||||||
path: /tmp/artifacts
|
|
||||||
- name: Download hi binary
|
|
||||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
||||||
with:
|
|
||||||
name: hi-binary
|
|
||||||
path: /tmp/artifacts
|
|
||||||
- name: Download Go cache
|
|
||||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
||||||
with:
|
|
||||||
name: go-cache
|
|
||||||
path: /tmp/artifacts
|
|
||||||
- name: Download postgres image
|
|
||||||
if: ${{ inputs.postgres_flag == '--postgres=1' }}
|
|
||||||
uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0
|
|
||||||
with:
|
|
||||||
name: postgres-image
|
|
||||||
path: /tmp/artifacts
|
|
||||||
- name: Pin Docker to v28 (avoid v29 breaking changes)
|
|
||||||
run: |
|
|
||||||
# Docker 29 breaks docker build via Go client libraries and
|
|
||||||
# docker load/save with certain tarball formats.
|
|
||||||
# Pin to Docker 28.x until our tooling is updated.
|
|
||||||
# https://github.com/actions/runner-images/issues/13474
|
|
||||||
sudo install -m 0755 -d /etc/apt/keyrings
|
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
|
|
||||||
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
|
||||||
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
|
||||||
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
||||||
sudo apt-get update -qq
|
|
||||||
VERSION=$(apt-cache madison docker-ce | grep '28\.5' | head -1 | awk '{print $3}')
|
|
||||||
sudo apt-get install -y --allow-downgrades \
|
|
||||||
"docker-ce=${VERSION}" "docker-ce-cli=${VERSION}"
|
|
||||||
sudo systemctl restart docker
|
|
||||||
docker version
|
|
||||||
- name: Load Docker images, Go cache, and prepare binary
|
|
||||||
run: |
|
|
||||||
gunzip -c /tmp/artifacts/headscale-image.tar.gz | docker load
|
|
||||||
gunzip -c /tmp/artifacts/tailscale-head-image.tar.gz | docker load
|
|
||||||
if [ -f /tmp/artifacts/postgres-image.tar.gz ]; then
|
|
||||||
gunzip -c /tmp/artifacts/postgres-image.tar.gz | docker load
|
|
||||||
fi
|
|
||||||
chmod +x /tmp/artifacts/hi
|
|
||||||
docker images
|
|
||||||
# Extract Go cache to host directories for bind mounting
|
|
||||||
mkdir -p /tmp/go-cache
|
|
||||||
tar -xzf /tmp/artifacts/go-cache.tar.gz -C /tmp/go-cache
|
|
||||||
ls -la /tmp/go-cache/ /tmp/go-cache/.cache/
|
|
||||||
- name: Run Integration Test
|
|
||||||
env:
|
|
||||||
HEADSCALE_INTEGRATION_HEADSCALE_IMAGE: headscale:${{ github.sha }}
|
|
||||||
HEADSCALE_INTEGRATION_TAILSCALE_IMAGE: tailscale-head:${{ github.sha }}
|
|
||||||
HEADSCALE_INTEGRATION_POSTGRES_IMAGE: ${{ inputs.postgres_flag == '--postgres=1' && format('postgres:{0}', github.sha) || '' }}
|
|
||||||
HEADSCALE_INTEGRATION_GO_CACHE: /tmp/go-cache/go
|
|
||||||
HEADSCALE_INTEGRATION_GO_BUILD_CACHE: /tmp/go-cache/.cache/go-build
|
|
||||||
run: /tmp/artifacts/hi run --stats --ts-memory-limit=300 --hs-memory-limit=1500 "^${{ inputs.test }}$" \
|
|
||||||
--timeout=120m \
|
|
||||||
${{ inputs.postgres_flag }}
|
|
||||||
# Sanitize test name for artifact upload (replace invalid characters: " : < > | * ? \ / with -)
|
|
||||||
- name: Sanitize test name for artifacts
|
|
||||||
if: always()
|
|
||||||
id: sanitize
|
|
||||||
run: echo "name=${TEST_NAME//[\":<>|*?\\\/]/-}" >> $GITHUB_OUTPUT
|
|
||||||
env:
|
|
||||||
TEST_NAME: ${{ inputs.test }}
|
|
||||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.database_name }}-${{ steps.sanitize.outputs.name }}-logs
|
|
||||||
path: "control_logs/*/*.log"
|
|
||||||
- uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
if: always()
|
|
||||||
with:
|
|
||||||
name: ${{ inputs.database_name }}-${{ steps.sanitize.outputs.name }}-artifacts
|
|
||||||
path: control_logs/
|
|
||||||
- name: Setup a blocking tmux session
|
|
||||||
if: ${{ env.HAS_TAILSCALE_SECRET }}
|
|
||||||
uses: alexellis/block-with-tmux-action@master
|
|
||||||
105
.github/workflows/lint.yml
vendored
105
.github/workflows/lint.yml
vendored
@@ -1,6 +1,7 @@
|
|||||||
|
---
|
||||||
name: Lint
|
name: Lint
|
||||||
|
|
||||||
on: [pull_request]
|
on: [push, pull_request]
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
@@ -10,84 +11,70 @@ jobs:
|
|||||||
golangci-lint:
|
golangci-lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
uses: tj-actions/changed-files@v34
|
||||||
with:
|
with:
|
||||||
filters: |
|
files: |
|
||||||
files:
|
*.nix
|
||||||
- '*.nix'
|
go.*
|
||||||
- 'go.*'
|
**/*.go
|
||||||
- '**/*.go'
|
integration_test/
|
||||||
- 'integration_test/'
|
config-example.yaml
|
||||||
- 'config-example.yaml'
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: golangci-lint
|
- name: golangci-lint
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: nix develop --command -- golangci-lint run
|
uses: golangci/golangci-lint-action@v2
|
||||||
--new-from-rev=${{github.event.pull_request.base.sha}}
|
with:
|
||||||
--output.text.path=stdout
|
version: v1.51.2
|
||||||
--output.text.print-linter-name
|
|
||||||
--output.text.print-issued-lines
|
# Only block PRs on new problems.
|
||||||
--output.text.colors
|
# If this is not enabled, we will end up having PRs
|
||||||
|
# blocked because new linters has appared and other
|
||||||
|
# parts of the code is affected.
|
||||||
|
only-new-issues: true
|
||||||
|
|
||||||
prettier-lint:
|
prettier-lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@v2
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
uses: tj-actions/changed-files@v14.1
|
||||||
with:
|
with:
|
||||||
filters: |
|
files: |
|
||||||
files:
|
*.nix
|
||||||
- '*.nix'
|
**/*.md
|
||||||
- '**/*.md'
|
**/*.yml
|
||||||
- '**/*.yml'
|
**/*.yaml
|
||||||
- '**/*.yaml'
|
**/*.ts
|
||||||
- '**/*.ts'
|
**/*.js
|
||||||
- '**/*.js'
|
**/*.sass
|
||||||
- '**/*.sass'
|
**/*.css
|
||||||
- '**/*.css'
|
**/*.scss
|
||||||
- '**/*.scss'
|
**/*.html
|
||||||
- '**/*.html'
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Prettify code
|
- name: Prettify code
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
run: nix develop --command -- prettier --no-error-on-unmatched-pattern
|
uses: creyD/prettier_action@v4.3
|
||||||
--ignore-unknown --check **/*.{ts,js,md,yaml,yml,sass,css,scss,html}
|
with:
|
||||||
|
prettier_options: >-
|
||||||
|
--check **/*.{ts,js,md,yaml,yml,sass,css,scss,html}
|
||||||
|
only_changed: false
|
||||||
|
dry: true
|
||||||
|
|
||||||
proto-lint:
|
proto-lint:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@v2
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
- uses: bufbuild/buf-setup-action@v1.7.0
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
- uses: bufbuild/buf-lint-action@v1
|
||||||
with:
|
with:
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
input: "proto"
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Buf lint
|
|
||||||
run: nix develop --command -- buf lint proto
|
|
||||||
|
|||||||
28
.github/workflows/needs-more-info-comment.yml
vendored
28
.github/workflows/needs-more-info-comment.yml
vendored
@@ -1,28 +0,0 @@
|
|||||||
name: Needs More Info - Post Comment
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [labeled]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
post-comment:
|
|
||||||
if: >-
|
|
||||||
github.event.label.name == 'needs-more-info' &&
|
|
||||||
github.repository == 'juanfont/headscale'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
with:
|
|
||||||
sparse-checkout: .github/label-response/needs-more-info.md
|
|
||||||
sparse-checkout-cone-mode: false
|
|
||||||
|
|
||||||
- name: Post instruction comment
|
|
||||||
run: gh issue comment "$NUMBER" --body-file .github/label-response/needs-more-info.md
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GH_REPO: ${{ github.repository }}
|
|
||||||
NUMBER: ${{ github.event.issue.number }}
|
|
||||||
98
.github/workflows/needs-more-info-timer.yml
vendored
98
.github/workflows/needs-more-info-timer.yml
vendored
@@ -1,98 +0,0 @@
|
|||||||
name: Needs More Info - Timer
|
|
||||||
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: "0 0 * * *" # Daily at midnight UTC
|
|
||||||
issue_comment:
|
|
||||||
types: [created]
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
# When a non-bot user comments on a needs-more-info issue, remove the label.
|
|
||||||
remove-label-on-response:
|
|
||||||
if: >-
|
|
||||||
github.repository == 'juanfont/headscale' &&
|
|
||||||
github.event_name == 'issue_comment' &&
|
|
||||||
github.event.comment.user.type != 'Bot' &&
|
|
||||||
contains(github.event.issue.labels.*.name, 'needs-more-info')
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
steps:
|
|
||||||
- name: Remove needs-more-info label
|
|
||||||
run: gh issue edit "$NUMBER" --remove-label needs-more-info
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GH_REPO: ${{ github.repository }}
|
|
||||||
NUMBER: ${{ github.event.issue.number }}
|
|
||||||
|
|
||||||
# On schedule, close issues that have had no human response for 3 days.
|
|
||||||
close-stale:
|
|
||||||
if: >-
|
|
||||||
github.repository == 'juanfont/headscale' &&
|
|
||||||
github.event_name != 'issue_comment'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
steps:
|
|
||||||
- uses: hustcer/setup-nu@920172d92eb04671776f3ba69d605d3b09351c30 # v3.22
|
|
||||||
with:
|
|
||||||
version: "*"
|
|
||||||
|
|
||||||
- name: Close stale needs-more-info issues
|
|
||||||
shell: nu {0}
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GH_REPO: ${{ github.repository }}
|
|
||||||
run: |
|
|
||||||
let issues = (gh issue list
|
|
||||||
--repo $env.GH_REPO
|
|
||||||
--label "needs-more-info"
|
|
||||||
--state open
|
|
||||||
--json number
|
|
||||||
| from json)
|
|
||||||
|
|
||||||
for issue in $issues {
|
|
||||||
let number = $issue.number
|
|
||||||
print $"Checking issue #($number)"
|
|
||||||
|
|
||||||
# Find when needs-more-info was last added
|
|
||||||
let events = (gh api $"repos/($env.GH_REPO)/issues/($number)/events"
|
|
||||||
--paginate | from json | flatten)
|
|
||||||
let label_event = ($events
|
|
||||||
| where event == "labeled" and label.name == "needs-more-info"
|
|
||||||
| last)
|
|
||||||
let label_added_at = ($label_event.created_at | into datetime)
|
|
||||||
|
|
||||||
# Check for non-bot comments after the label was added
|
|
||||||
let comments = (gh api $"repos/($env.GH_REPO)/issues/($number)/comments"
|
|
||||||
--paginate | from json | flatten)
|
|
||||||
let human_responses = ($comments
|
|
||||||
| where user.type != "Bot"
|
|
||||||
| where { ($in.created_at | into datetime) > $label_added_at })
|
|
||||||
|
|
||||||
if ($human_responses | length) > 0 {
|
|
||||||
print $" Human responded, removing label"
|
|
||||||
gh issue edit $number --repo $env.GH_REPO --remove-label needs-more-info
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
# Check if 3 days have passed
|
|
||||||
let elapsed = (date now) - $label_added_at
|
|
||||||
if $elapsed < 3day {
|
|
||||||
print $" Only ($elapsed | format duration day) elapsed, skipping"
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
print $" No response for ($elapsed | format duration day), closing"
|
|
||||||
let message = [
|
|
||||||
"This issue has been automatically closed because no additional information was provided within 3 days."
|
|
||||||
""
|
|
||||||
"If you have the requested information, please open a new issue and include the debug information requested above."
|
|
||||||
""
|
|
||||||
"Thank you for your understanding."
|
|
||||||
] | str join "\n"
|
|
||||||
gh issue comment $number --repo $env.GH_REPO --body $message
|
|
||||||
gh issue close $number --repo $env.GH_REPO --reason "not planned"
|
|
||||||
gh issue edit $number --repo $env.GH_REPO --remove-label needs-more-info
|
|
||||||
}
|
|
||||||
55
.github/workflows/nix-module-test.yml
vendored
55
.github/workflows/nix-module-test.yml
vendored
@@ -1,55 +0,0 @@
|
|||||||
name: NixOS Module Tests
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
nix-module-check:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
|
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
nix:
|
|
||||||
- 'nix/**'
|
|
||||||
- 'flake.nix'
|
|
||||||
- 'flake.lock'
|
|
||||||
go:
|
|
||||||
- 'go.*'
|
|
||||||
- '**/*.go'
|
|
||||||
- 'cmd/**'
|
|
||||||
- 'hscontrol/**'
|
|
||||||
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.nix == 'true' || steps.changed-files.outputs.go == 'true'
|
|
||||||
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.nix == 'true' || steps.changed-files.outputs.go == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Run NixOS module tests
|
|
||||||
if: steps.changed-files.outputs.nix == 'true' || steps.changed-files.outputs.go == 'true'
|
|
||||||
run: |
|
|
||||||
echo "Running NixOS module integration test..."
|
|
||||||
nix build .#checks.x86_64-linux.headscale -L
|
|
||||||
138
.github/workflows/release-docker.yml
vendored
Normal file
138
.github/workflows/release-docker.yml
vendored
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
---
|
||||||
|
name: Release Docker
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- "*" # triggers only if push new tag version
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
docker-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
- name: Set up QEMU for multiple platforms
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: arm64,amd64
|
||||||
|
- name: Cache Docker layers
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache
|
||||||
|
key: ${{ runner.os }}-buildx-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
# list of Docker images to use as base name for tags
|
||||||
|
images: |
|
||||||
|
${{ secrets.DOCKERHUB_USERNAME }}/headscale
|
||||||
|
ghcr.io/${{ github.repository_owner }}/headscale
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
type=sha
|
||||||
|
type=raw,value=develop
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Login to GHCR
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
context: .
|
||||||
|
tags: ${{ steps.meta.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta.outputs.labels }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-new
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ steps.meta.outputs.version }}
|
||||||
|
- name: Prepare cache for next build
|
||||||
|
run: |
|
||||||
|
rm -rf /tmp/.buildx-cache
|
||||||
|
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
|
||||||
|
|
||||||
|
docker-debug-release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
- name: Set up Docker Buildx
|
||||||
|
uses: docker/setup-buildx-action@v1
|
||||||
|
- name: Set up QEMU for multiple platforms
|
||||||
|
uses: docker/setup-qemu-action@master
|
||||||
|
with:
|
||||||
|
platforms: arm64,amd64
|
||||||
|
- name: Cache Docker layers
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: /tmp/.buildx-cache-debug
|
||||||
|
key: ${{ runner.os }}-buildx-debug-${{ github.sha }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-buildx-debug-
|
||||||
|
- name: Docker meta
|
||||||
|
id: meta-debug
|
||||||
|
uses: docker/metadata-action@v3
|
||||||
|
with:
|
||||||
|
# list of Docker images to use as base name for tags
|
||||||
|
images: |
|
||||||
|
${{ secrets.DOCKERHUB_USERNAME }}/headscale
|
||||||
|
ghcr.io/${{ github.repository_owner }}/headscale
|
||||||
|
flavor: |
|
||||||
|
suffix=-debug,onlatest=true
|
||||||
|
tags: |
|
||||||
|
type=semver,pattern={{version}}
|
||||||
|
type=semver,pattern={{major}}.{{minor}}
|
||||||
|
type=semver,pattern={{major}}
|
||||||
|
type=sha
|
||||||
|
type=raw,value=develop
|
||||||
|
- name: Login to DockerHub
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||||
|
- name: Login to GHCR
|
||||||
|
uses: docker/login-action@v1
|
||||||
|
with:
|
||||||
|
registry: ghcr.io
|
||||||
|
username: ${{ github.repository_owner }}
|
||||||
|
password: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Build and push
|
||||||
|
id: docker_build
|
||||||
|
uses: docker/build-push-action@v2
|
||||||
|
with:
|
||||||
|
push: true
|
||||||
|
context: .
|
||||||
|
file: Dockerfile.debug
|
||||||
|
tags: ${{ steps.meta-debug.outputs.tags }}
|
||||||
|
labels: ${{ steps.meta-debug.outputs.labels }}
|
||||||
|
platforms: linux/amd64,linux/arm64
|
||||||
|
cache-from: type=local,src=/tmp/.buildx-cache-debug
|
||||||
|
cache-to: type=local,dest=/tmp/.buildx-cache-debug-new
|
||||||
|
build-args: |
|
||||||
|
VERSION=${{ steps.meta-debug.outputs.version }}
|
||||||
|
- name: Prepare cache for next build
|
||||||
|
run: |
|
||||||
|
rm -rf /tmp/.buildx-cache-debug
|
||||||
|
mv /tmp/.buildx-cache-debug-new /tmp/.buildx-cache-debug
|
||||||
43
.github/workflows/release.yml
vendored
43
.github/workflows/release.yml
vendored
@@ -9,52 +9,15 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
goreleaser:
|
goreleaser:
|
||||||
if: github.repository == 'juanfont/headscale'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Pin Docker to v28 (avoid v29 breaking changes)
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
run: |
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
# Docker 29 breaks docker build via Go client libraries and
|
|
||||||
# docker load/save with certain tarball formats.
|
|
||||||
# Pin to Docker 28.x until our tooling is updated.
|
|
||||||
# https://github.com/actions/runner-images/issues/13474
|
|
||||||
sudo install -m 0755 -d /etc/apt/keyrings
|
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
|
|
||||||
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
|
||||||
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
|
||||||
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
||||||
sudo apt-get update -qq
|
|
||||||
VERSION=$(apt-cache madison docker-ce | grep '28\.5' | head -1 | awk '{print $3}')
|
|
||||||
sudo apt-get install -y --allow-downgrades \
|
|
||||||
"docker-ce=${VERSION}" "docker-ce-cli=${VERSION}"
|
|
||||||
sudo systemctl restart docker
|
|
||||||
docker version
|
|
||||||
|
|
||||||
- name: Login to DockerHub
|
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
|
||||||
with:
|
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Login to GHCR
|
|
||||||
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
|
|
||||||
with:
|
|
||||||
registry: ghcr.io
|
|
||||||
username: ${{ github.repository_owner }}
|
|
||||||
password: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Run goreleaser
|
- name: Run goreleaser
|
||||||
run: nix develop --command -- goreleaser release --clean
|
run: nix develop --command -- goreleaser release --clean
|
||||||
|
|||||||
11
.github/workflows/stale.yml
vendored
11
.github/workflows/stale.yml
vendored
@@ -1,27 +1,22 @@
|
|||||||
name: Close inactive issues
|
name: Close inactive issues
|
||||||
|
|
||||||
on:
|
on:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: "30 1 * * *"
|
- cron: "30 1 * * *"
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
close-issues:
|
close-issues:
|
||||||
if: github.repository == 'juanfont/headscale'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
permissions:
|
permissions:
|
||||||
issues: write
|
issues: write
|
||||||
pull-requests: write
|
pull-requests: write
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/stale@997185467fa4f803885201cee163a9f38240193d # v10.1.1
|
- uses: actions/stale@v5
|
||||||
with:
|
with:
|
||||||
days-before-issue-stale: 90
|
days-before-issue-stale: 90
|
||||||
days-before-issue-close: 7
|
days-before-issue-close: 7
|
||||||
stale-issue-label: "stale"
|
stale-issue-label: "stale"
|
||||||
stale-issue-message: "This issue is stale because it has been open for 90 days with no
|
stale-issue-message: "This issue is stale because it has been open for 90 days with no activity."
|
||||||
activity."
|
close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale."
|
||||||
close-issue-message: "This issue was closed because it has been inactive for 14 days
|
|
||||||
since being marked as stale."
|
|
||||||
days-before-pr-stale: -1
|
days-before-pr-stale: -1
|
||||||
days-before-pr-close: -1
|
days-before-pr-close: -1
|
||||||
exempt-issue-labels: "no-stale-bot,needs-more-info"
|
|
||||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|||||||
30
.github/workflows/support-request.yml
vendored
30
.github/workflows/support-request.yml
vendored
@@ -1,30 +0,0 @@
|
|||||||
name: Support Request - Close Issue
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [labeled]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
close-support-request:
|
|
||||||
if: >-
|
|
||||||
github.event.label.name == 'support-request' &&
|
|
||||||
github.repository == 'juanfont/headscale'
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
permissions:
|
|
||||||
issues: write
|
|
||||||
contents: read
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
|
||||||
with:
|
|
||||||
sparse-checkout: .github/label-response/support-request.md
|
|
||||||
sparse-checkout-cone-mode: false
|
|
||||||
|
|
||||||
- name: Post comment and close issue
|
|
||||||
run: |
|
|
||||||
gh issue comment "$NUMBER" --body-file .github/label-response/support-request.md
|
|
||||||
gh issue close "$NUMBER" --reason "not planned"
|
|
||||||
env:
|
|
||||||
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
GH_REPO: ${{ github.repository }}
|
|
||||||
NUMBER: ${{ github.event.issue.number }}
|
|
||||||
67
.github/workflows/test-integration-v2-TestACLAllowStarDst.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLAllowStarDst.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLAllowStarDst
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLAllowStarDst:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLAllowStarDst
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLAllowStarDst$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLAllowUser80Dst.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLAllowUser80Dst.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLAllowUser80Dst
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLAllowUser80Dst:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLAllowUser80Dst
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLAllowUser80Dst$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLAllowUserDst.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLAllowUserDst.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLAllowUserDst
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLAllowUserDst:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLAllowUserDst
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLAllowUserDst$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLDenyAllPort80.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLDenyAllPort80.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLDenyAllPort80
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLDenyAllPort80:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLDenyAllPort80
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLDenyAllPort80$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLDevice1CanAccessDevice2.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLDevice1CanAccessDevice2.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLDevice1CanAccessDevice2
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLDevice1CanAccessDevice2:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLDevice1CanAccessDevice2
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLDevice1CanAccessDevice2$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLHostsInNetMapTable.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLHostsInNetMapTable.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLHostsInNetMapTable
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLHostsInNetMapTable:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLHostsInNetMapTable
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLHostsInNetMapTable$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLNamedHostsCanReach.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLNamedHostsCanReach.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLNamedHostsCanReach
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLNamedHostsCanReach:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLNamedHostsCanReach
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLNamedHostsCanReach$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestACLNamedHostsCanReachBySubnet.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestACLNamedHostsCanReachBySubnet.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestACLNamedHostsCanReachBySubnet
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestACLNamedHostsCanReachBySubnet:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestACLNamedHostsCanReachBySubnet
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestACLNamedHostsCanReachBySubnet$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestApiKeyCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestApiKeyCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestApiKeyCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestApiKeyCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestApiKeyCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestApiKeyCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestAuthKeyLogoutAndRelogin.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestAuthKeyLogoutAndRelogin.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestAuthKeyLogoutAndRelogin
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestAuthKeyLogoutAndRelogin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestAuthKeyLogoutAndRelogin
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestAuthKeyLogoutAndRelogin$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestAuthWebFlowAuthenticationPingAll.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestAuthWebFlowAuthenticationPingAll.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestAuthWebFlowAuthenticationPingAll
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestAuthWebFlowAuthenticationPingAll:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestAuthWebFlowAuthenticationPingAll
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestAuthWebFlowAuthenticationPingAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestAuthWebFlowLogoutAndRelogin.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestAuthWebFlowLogoutAndRelogin.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestAuthWebFlowLogoutAndRelogin
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestAuthWebFlowLogoutAndRelogin:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestAuthWebFlowLogoutAndRelogin
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestAuthWebFlowLogoutAndRelogin$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestCreateTailscale.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestCreateTailscale.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestCreateTailscale
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestCreateTailscale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestCreateTailscale
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestCreateTailscale$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestDERPServerScenario.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestDERPServerScenario.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestDERPServerScenario
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestDERPServerScenario:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestDERPServerScenario
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestDERPServerScenario$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestEnablingRoutes.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestEnablingRoutes.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestEnablingRoutes
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestEnablingRoutes:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestEnablingRoutes
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestEnablingRoutes$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestEphemeral.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestEphemeral.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestEphemeral
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestEphemeral:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestEphemeral
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestEphemeral$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestExpireNode.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestExpireNode.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestExpireNode
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestExpireNode:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestExpireNode
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestExpireNode$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestHASubnetRouterFailover.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestHASubnetRouterFailover.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestHASubnetRouterFailover
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestHASubnetRouterFailover:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestHASubnetRouterFailover
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestHASubnetRouterFailover$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestHeadscale.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestHeadscale.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestHeadscale
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestHeadscale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestHeadscale
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestHeadscale$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestNodeCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestNodeCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestNodeCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNodeCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestNodeCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestNodeCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestNodeExpireCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestNodeExpireCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestNodeExpireCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNodeExpireCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestNodeExpireCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestNodeExpireCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestNodeMoveCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestNodeMoveCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestNodeMoveCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNodeMoveCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestNodeMoveCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestNodeMoveCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestNodeOnlineLastSeenStatus.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestNodeOnlineLastSeenStatus.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestNodeOnlineLastSeenStatus
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNodeOnlineLastSeenStatus:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestNodeOnlineLastSeenStatus
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestNodeOnlineLastSeenStatus$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestNodeRenameCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestNodeRenameCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestNodeRenameCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNodeRenameCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestNodeRenameCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestNodeRenameCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestNodeTagCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestNodeTagCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestNodeTagCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestNodeTagCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestNodeTagCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestNodeTagCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestOIDCAuthenticationPingAll.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestOIDCAuthenticationPingAll.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestOIDCAuthenticationPingAll
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestOIDCAuthenticationPingAll:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestOIDCAuthenticationPingAll
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestOIDCAuthenticationPingAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestOIDCExpireNodesBasedOnTokenExpiry.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestOIDCExpireNodesBasedOnTokenExpiry.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestOIDCExpireNodesBasedOnTokenExpiry
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestOIDCExpireNodesBasedOnTokenExpiry:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestOIDCExpireNodesBasedOnTokenExpiry
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestOIDCExpireNodesBasedOnTokenExpiry$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestPingAllByHostname.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestPingAllByHostname.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestPingAllByHostname
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestPingAllByHostname:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestPingAllByHostname
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestPingAllByHostname$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestPingAllByIP.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestPingAllByIP.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestPingAllByIP
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestPingAllByIP:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestPingAllByIP
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestPingAllByIP$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestPreAuthKeyCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestPreAuthKeyCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestPreAuthKeyCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestPreAuthKeyCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestPreAuthKeyCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestPreAuthKeyCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestPreAuthKeyCommandReusableEphemeral.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestPreAuthKeyCommandReusableEphemeral.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestPreAuthKeyCommandReusableEphemeral
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestPreAuthKeyCommandReusableEphemeral:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestPreAuthKeyCommandReusableEphemeral
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestPreAuthKeyCommandReusableEphemeral$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestPreAuthKeyCommandWithoutExpiry.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestPreAuthKeyCommandWithoutExpiry.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestPreAuthKeyCommandWithoutExpiry
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestPreAuthKeyCommandWithoutExpiry:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestPreAuthKeyCommandWithoutExpiry
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestPreAuthKeyCommandWithoutExpiry$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestResolveMagicDNS.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestResolveMagicDNS.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestResolveMagicDNS
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestResolveMagicDNS:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestResolveMagicDNS
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestResolveMagicDNS$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestSSHIsBlockedInACL.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestSSHIsBlockedInACL.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestSSHIsBlockedInACL
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestSSHIsBlockedInACL:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestSSHIsBlockedInACL
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestSSHIsBlockedInACL$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestSSHMultipleUsersAllToAll.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestSSHMultipleUsersAllToAll.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestSSHMultipleUsersAllToAll
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestSSHMultipleUsersAllToAll:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestSSHMultipleUsersAllToAll
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestSSHMultipleUsersAllToAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestSSHNoSSHConfigured.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestSSHNoSSHConfigured.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestSSHNoSSHConfigured
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestSSHNoSSHConfigured:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestSSHNoSSHConfigured
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestSSHNoSSHConfigured$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestSSHOneUserToAll.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestSSHOneUserToAll.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestSSHOneUserToAll
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestSSHOneUserToAll:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestSSHOneUserToAll
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestSSHOneUserToAll$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestSSHUserOnlyIsolation.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestSSHUserOnlyIsolation.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestSSHUserOnlyIsolation
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestSSHUserOnlyIsolation:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestSSHUserOnlyIsolation
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestSSHUserOnlyIsolation$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestTaildrop.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestTaildrop.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestTaildrop
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestTaildrop:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestTaildrop
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestTaildrop$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestTailscaleNodesJoiningHeadcale.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestTailscaleNodesJoiningHeadcale.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestTailscaleNodesJoiningHeadcale
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestTailscaleNodesJoiningHeadcale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestTailscaleNodesJoiningHeadcale
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestTailscaleNodesJoiningHeadcale$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
67
.github/workflows/test-integration-v2-TestUserCommand.yaml
vendored
Normal file
67
.github/workflows/test-integration-v2-TestUserCommand.yaml
vendored
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - TestUserCommand
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-$${{ github.head_ref || github.run_id }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
TestUserCommand:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run TestUserCommand
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^TestUserCommand$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
318
.github/workflows/test-integration.yaml
vendored
318
.github/workflows/test-integration.yaml
vendored
@@ -1,318 +0,0 @@
|
|||||||
name: integration
|
|
||||||
# To debug locally on a branch, and when needing secrets
|
|
||||||
# change this to include `push` so the build is ran on
|
|
||||||
# the main repository.
|
|
||||||
on: [pull_request]
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
jobs:
|
|
||||||
# build: Builds binaries and Docker images once, uploads as artifacts for reuse.
|
|
||||||
# build-postgres: Pulls postgres image separately to avoid Docker Hub rate limits.
|
|
||||||
# sqlite: Runs all integration tests with SQLite backend.
|
|
||||||
# postgres: Runs a subset of tests with PostgreSQL to verify database compatibility.
|
|
||||||
build:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
outputs:
|
|
||||||
files-changed: ${{ steps.changed-files.outputs.files }}
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
|
||||||
with:
|
|
||||||
fetch-depth: 2
|
|
||||||
- name: Get changed files
|
|
||||||
id: changed-files
|
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
|
||||||
with:
|
|
||||||
filters: |
|
|
||||||
files:
|
|
||||||
- '*.nix'
|
|
||||||
- 'go.*'
|
|
||||||
- '**/*.go'
|
|
||||||
- 'integration/**'
|
|
||||||
- 'config-example.yaml'
|
|
||||||
- '.github/workflows/test-integration.yaml'
|
|
||||||
- '.github/workflows/integration-test-template.yml'
|
|
||||||
- 'Dockerfile.*'
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix', '**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
- name: Build binaries and warm Go cache
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
# Build all Go binaries in one nix shell to maximize cache reuse
|
|
||||||
nix develop --command -- bash -c '
|
|
||||||
go build -o hi ./cmd/hi
|
|
||||||
CGO_ENABLED=0 GOOS=linux go build -o headscale ./cmd/headscale
|
|
||||||
# Build integration test binary to warm the cache with all dependencies
|
|
||||||
go test -c ./integration -o /dev/null 2>/dev/null || true
|
|
||||||
'
|
|
||||||
- name: Upload hi binary
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
with:
|
|
||||||
name: hi-binary
|
|
||||||
path: hi
|
|
||||||
retention-days: 10
|
|
||||||
- name: Package Go cache
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
# Package Go module cache and build cache
|
|
||||||
tar -czf go-cache.tar.gz -C ~ go .cache/go-build
|
|
||||||
- name: Upload Go cache
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
with:
|
|
||||||
name: go-cache
|
|
||||||
path: go-cache.tar.gz
|
|
||||||
retention-days: 10
|
|
||||||
- name: Pin Docker to v28 (avoid v29 breaking changes)
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
# Docker 29 breaks docker build via Go client libraries and
|
|
||||||
# docker load/save with certain tarball formats.
|
|
||||||
# Pin to Docker 28.x until our tooling is updated.
|
|
||||||
# https://github.com/actions/runner-images/issues/13474
|
|
||||||
sudo install -m 0755 -d /etc/apt/keyrings
|
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
|
|
||||||
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
|
||||||
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
|
||||||
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
||||||
sudo apt-get update -qq
|
|
||||||
VERSION=$(apt-cache madison docker-ce | grep '28\.5' | head -1 | awk '{print $3}')
|
|
||||||
sudo apt-get install -y --allow-downgrades \
|
|
||||||
"docker-ce=${VERSION}" "docker-ce-cli=${VERSION}"
|
|
||||||
sudo systemctl restart docker
|
|
||||||
docker version
|
|
||||||
- name: Build headscale image
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
docker build \
|
|
||||||
--file Dockerfile.integration-ci \
|
|
||||||
--tag headscale:${{ github.sha }} \
|
|
||||||
.
|
|
||||||
docker save headscale:${{ github.sha }} | gzip > headscale-image.tar.gz
|
|
||||||
- name: Build tailscale HEAD image
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
run: |
|
|
||||||
docker build \
|
|
||||||
--file Dockerfile.tailscale-HEAD \
|
|
||||||
--tag tailscale-head:${{ github.sha }} \
|
|
||||||
.
|
|
||||||
docker save tailscale-head:${{ github.sha }} | gzip > tailscale-head-image.tar.gz
|
|
||||||
- name: Upload headscale image
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
with:
|
|
||||||
name: headscale-image
|
|
||||||
path: headscale-image.tar.gz
|
|
||||||
retention-days: 10
|
|
||||||
- name: Upload tailscale HEAD image
|
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
|
||||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
with:
|
|
||||||
name: tailscale-head-image
|
|
||||||
path: tailscale-head-image.tar.gz
|
|
||||||
retention-days: 10
|
|
||||||
build-postgres:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: build
|
|
||||||
if: needs.build.outputs.files-changed == 'true'
|
|
||||||
steps:
|
|
||||||
- name: Pin Docker to v28 (avoid v29 breaking changes)
|
|
||||||
run: |
|
|
||||||
# Docker 29 breaks docker build via Go client libraries and
|
|
||||||
# docker load/save with certain tarball formats.
|
|
||||||
# Pin to Docker 28.x until our tooling is updated.
|
|
||||||
# https://github.com/actions/runner-images/issues/13474
|
|
||||||
sudo install -m 0755 -d /etc/apt/keyrings
|
|
||||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
|
|
||||||
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
|
||||||
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
|
|
||||||
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
|
|
||||||
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
|
||||||
sudo apt-get update -qq
|
|
||||||
VERSION=$(apt-cache madison docker-ce | grep '28\.5' | head -1 | awk '{print $3}')
|
|
||||||
sudo apt-get install -y --allow-downgrades \
|
|
||||||
"docker-ce=${VERSION}" "docker-ce-cli=${VERSION}"
|
|
||||||
sudo systemctl restart docker
|
|
||||||
docker version
|
|
||||||
- name: Pull and save postgres image
|
|
||||||
run: |
|
|
||||||
docker pull postgres:latest
|
|
||||||
docker tag postgres:latest postgres:${{ github.sha }}
|
|
||||||
docker save postgres:${{ github.sha }} | gzip > postgres-image.tar.gz
|
|
||||||
- name: Upload postgres image
|
|
||||||
uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0
|
|
||||||
with:
|
|
||||||
name: postgres-image
|
|
||||||
path: postgres-image.tar.gz
|
|
||||||
retention-days: 10
|
|
||||||
sqlite:
|
|
||||||
needs: build
|
|
||||||
if: needs.build.outputs.files-changed == 'true'
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
test:
|
|
||||||
- TestACLHostsInNetMapTable
|
|
||||||
- TestACLAllowUser80Dst
|
|
||||||
- TestACLDenyAllPort80
|
|
||||||
- TestACLAllowUserDst
|
|
||||||
- TestACLAllowStarDst
|
|
||||||
- TestACLNamedHostsCanReachBySubnet
|
|
||||||
- TestACLNamedHostsCanReach
|
|
||||||
- TestACLDevice1CanAccessDevice2
|
|
||||||
- TestPolicyUpdateWhileRunningWithCLIInDatabase
|
|
||||||
- TestACLAutogroupMember
|
|
||||||
- TestACLAutogroupTagged
|
|
||||||
- TestACLAutogroupSelf
|
|
||||||
- TestACLPolicyPropagationOverTime
|
|
||||||
- TestACLTagPropagation
|
|
||||||
- TestACLTagPropagationPortSpecific
|
|
||||||
- TestACLGroupWithUnknownUser
|
|
||||||
- TestACLGroupAfterUserDeletion
|
|
||||||
- TestACLGroupDeletionExactReproduction
|
|
||||||
- TestACLDynamicUnknownUserAddition
|
|
||||||
- TestACLDynamicUnknownUserRemoval
|
|
||||||
- TestAPIAuthenticationBypass
|
|
||||||
- TestAPIAuthenticationBypassCurl
|
|
||||||
- TestGRPCAuthenticationBypass
|
|
||||||
- TestCLIWithConfigAuthenticationBypass
|
|
||||||
- TestAuthKeyLogoutAndReloginSameUser
|
|
||||||
- TestAuthKeyLogoutAndReloginNewUser
|
|
||||||
- TestAuthKeyLogoutAndReloginSameUserExpiredKey
|
|
||||||
- TestAuthKeyDeleteKey
|
|
||||||
- TestAuthKeyLogoutAndReloginRoutesPreserved
|
|
||||||
- TestOIDCAuthenticationPingAll
|
|
||||||
- TestOIDCExpireNodesBasedOnTokenExpiry
|
|
||||||
- TestOIDC024UserCreation
|
|
||||||
- TestOIDCAuthenticationWithPKCE
|
|
||||||
- TestOIDCReloginSameNodeNewUser
|
|
||||||
- TestOIDCFollowUpUrl
|
|
||||||
- TestOIDCMultipleOpenedLoginUrls
|
|
||||||
- TestOIDCReloginSameNodeSameUser
|
|
||||||
- TestOIDCExpiryAfterRestart
|
|
||||||
- TestOIDCACLPolicyOnJoin
|
|
||||||
- TestOIDCReloginSameUserRoutesPreserved
|
|
||||||
- TestAuthWebFlowAuthenticationPingAll
|
|
||||||
- TestAuthWebFlowLogoutAndReloginSameUser
|
|
||||||
- TestAuthWebFlowLogoutAndReloginNewUser
|
|
||||||
- TestUserCommand
|
|
||||||
- TestPreAuthKeyCommand
|
|
||||||
- TestPreAuthKeyCommandWithoutExpiry
|
|
||||||
- TestPreAuthKeyCommandReusableEphemeral
|
|
||||||
- TestPreAuthKeyCorrectUserLoggedInCommand
|
|
||||||
- TestTaggedNodesCLIOutput
|
|
||||||
- TestApiKeyCommand
|
|
||||||
- TestNodeCommand
|
|
||||||
- TestNodeExpireCommand
|
|
||||||
- TestNodeRenameCommand
|
|
||||||
- TestPolicyCommand
|
|
||||||
- TestPolicyBrokenConfigCommand
|
|
||||||
- TestDERPVerifyEndpoint
|
|
||||||
- TestResolveMagicDNS
|
|
||||||
- TestResolveMagicDNSExtraRecordsPath
|
|
||||||
- TestDERPServerScenario
|
|
||||||
- TestDERPServerWebsocketScenario
|
|
||||||
- TestPingAllByIP
|
|
||||||
- TestPingAllByIPPublicDERP
|
|
||||||
- TestEphemeral
|
|
||||||
- TestEphemeralInAlternateTimezone
|
|
||||||
- TestEphemeral2006DeletedTooQuickly
|
|
||||||
- TestPingAllByHostname
|
|
||||||
- TestTaildrop
|
|
||||||
- TestUpdateHostnameFromClient
|
|
||||||
- TestExpireNode
|
|
||||||
- TestSetNodeExpiryInFuture
|
|
||||||
- TestDisableNodeExpiry
|
|
||||||
- TestNodeOnlineStatus
|
|
||||||
- TestPingAllByIPManyUpDown
|
|
||||||
- Test2118DeletingOnlineNodePanics
|
|
||||||
- TestEnablingRoutes
|
|
||||||
- TestHASubnetRouterFailover
|
|
||||||
- TestSubnetRouteACL
|
|
||||||
- TestEnablingExitRoutes
|
|
||||||
- TestSubnetRouterMultiNetwork
|
|
||||||
- TestSubnetRouterMultiNetworkExitNode
|
|
||||||
- TestAutoApproveMultiNetwork/authkey-tag.*
|
|
||||||
- TestAutoApproveMultiNetwork/authkey-user.*
|
|
||||||
- TestAutoApproveMultiNetwork/authkey-group.*
|
|
||||||
- TestAutoApproveMultiNetwork/webauth-tag.*
|
|
||||||
- TestAutoApproveMultiNetwork/webauth-user.*
|
|
||||||
- TestAutoApproveMultiNetwork/webauth-group.*
|
|
||||||
- TestSubnetRouteACLFiltering
|
|
||||||
- TestHeadscale
|
|
||||||
- TestTailscaleNodesJoiningHeadcale
|
|
||||||
- TestSSHOneUserToAll
|
|
||||||
- TestSSHMultipleUsersAllToAll
|
|
||||||
- TestSSHNoSSHConfigured
|
|
||||||
- TestSSHIsBlockedInACL
|
|
||||||
- TestSSHUserOnlyIsolation
|
|
||||||
- TestSSHAutogroupSelf
|
|
||||||
- TestSSHOneUserToOneCheckModeCLI
|
|
||||||
- TestSSHOneUserToOneCheckModeOIDC
|
|
||||||
- TestSSHCheckModeUnapprovedTimeout
|
|
||||||
- TestSSHCheckModeCheckPeriodCLI
|
|
||||||
- TestSSHCheckModeAutoApprove
|
|
||||||
- TestSSHCheckModeNegativeCLI
|
|
||||||
- TestTagsAuthKeyWithTagRequestDifferentTag
|
|
||||||
- TestTagsAuthKeyWithTagNoAdvertiseFlag
|
|
||||||
- TestTagsAuthKeyWithTagCannotAddViaCLI
|
|
||||||
- TestTagsAuthKeyWithTagCannotChangeViaCLI
|
|
||||||
- TestTagsAuthKeyWithTagAdminOverrideReauthPreserves
|
|
||||||
- TestTagsAuthKeyWithTagCLICannotModifyAdminTags
|
|
||||||
- TestTagsAuthKeyWithoutTagCannotRequestTags
|
|
||||||
- TestTagsAuthKeyWithoutTagRegisterNoTags
|
|
||||||
- TestTagsAuthKeyWithoutTagCannotAddViaCLI
|
|
||||||
- TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithReset
|
|
||||||
- TestTagsAuthKeyWithoutTagCLINoOpAfterAdminWithEmptyAdvertise
|
|
||||||
- TestTagsAuthKeyWithoutTagCLICannotReduceAdminMultiTag
|
|
||||||
- TestTagsUserLoginOwnedTagAtRegistration
|
|
||||||
- TestTagsUserLoginNonExistentTagAtRegistration
|
|
||||||
- TestTagsUserLoginUnownedTagAtRegistration
|
|
||||||
- TestTagsUserLoginAddTagViaCLIReauth
|
|
||||||
- TestTagsUserLoginRemoveTagViaCLIReauth
|
|
||||||
- TestTagsUserLoginCLINoOpAfterAdminAssignment
|
|
||||||
- TestTagsUserLoginCLICannotRemoveAdminTags
|
|
||||||
- TestTagsAuthKeyWithTagRequestNonExistentTag
|
|
||||||
- TestTagsAuthKeyWithTagRequestUnownedTag
|
|
||||||
- TestTagsAuthKeyWithoutTagRequestNonExistentTag
|
|
||||||
- TestTagsAuthKeyWithoutTagRequestUnownedTag
|
|
||||||
- TestTagsAdminAPICannotSetNonExistentTag
|
|
||||||
- TestTagsAdminAPICanSetUnownedTag
|
|
||||||
- TestTagsAdminAPICannotRemoveAllTags
|
|
||||||
- TestTagsIssue2978ReproTagReplacement
|
|
||||||
- TestTagsAdminAPICannotSetInvalidFormat
|
|
||||||
- TestTagsUserLoginReauthWithEmptyTagsRemovesAllTags
|
|
||||||
- TestTagsAuthKeyWithoutUserInheritsTags
|
|
||||||
- TestTagsAuthKeyWithoutUserRejectsAdvertisedTags
|
|
||||||
- TestTagsAuthKeyConvertToUserViaCLIRegister
|
|
||||||
uses: ./.github/workflows/integration-test-template.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
test: ${{ matrix.test }}
|
|
||||||
postgres_flag: "--postgres=0"
|
|
||||||
database_name: "sqlite"
|
|
||||||
postgres:
|
|
||||||
needs: [build, build-postgres]
|
|
||||||
if: needs.build.outputs.files-changed == 'true'
|
|
||||||
strategy:
|
|
||||||
fail-fast: false
|
|
||||||
matrix:
|
|
||||||
test:
|
|
||||||
- TestACLAllowUserDst
|
|
||||||
- TestPingAllByIP
|
|
||||||
- TestEphemeral2006DeletedTooQuickly
|
|
||||||
- TestPingAllByIPManyUpDown
|
|
||||||
- TestSubnetRouterMultiNetwork
|
|
||||||
uses: ./.github/workflows/integration-test-template.yml
|
|
||||||
secrets: inherit
|
|
||||||
with:
|
|
||||||
test: ${{ matrix.test }}
|
|
||||||
postgres_flag: "--postgres=1"
|
|
||||||
database_name: "postgres"
|
|
||||||
39
.github/workflows/test.yml
vendored
39
.github/workflows/test.yml
vendored
@@ -11,37 +11,26 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
|
- uses: actions/checkout@v3
|
||||||
with:
|
with:
|
||||||
fetch-depth: 2
|
fetch-depth: 2
|
||||||
|
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2
|
uses: tj-actions/changed-files@v34
|
||||||
with:
|
with:
|
||||||
filters: |
|
files: |
|
||||||
files:
|
*.nix
|
||||||
- '*.nix'
|
go.*
|
||||||
- 'go.*'
|
**/*.go
|
||||||
- '**/*.go'
|
integration_test/
|
||||||
- 'integration_test/'
|
config-example.yaml
|
||||||
- 'config-example.yaml'
|
|
||||||
|
|
||||||
- uses: nixbuild/nix-quick-install-action@2c9db80fb984ceb1bcaa77cdda3fdf8cfba92035 # v34
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
- uses: nix-community/cache-nix-action@135667ec418502fa5a3598af6fb9eb733888ce6a # v6.1.3
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
with:
|
|
||||||
primary-key: nix-${{ runner.os }}-${{ runner.arch }}-${{ hashFiles('**/*.nix',
|
|
||||||
'**/flake.lock') }}
|
|
||||||
restore-prefixes-first-match: nix-${{ runner.os }}-${{ runner.arch }}
|
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
if: steps.changed-files.outputs.files == 'true'
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
env:
|
run: nix develop --check
|
||||||
# As of 2025-01-06, these env vars was not automatically
|
|
||||||
# set anymore which breaks the initdb for postgres on
|
|
||||||
# some of the database migration tests.
|
|
||||||
LC_ALL: "en_US.UTF-8"
|
|
||||||
LC_CTYPE: "en_US.UTF-8"
|
|
||||||
run: nix develop --command -- gotestsum
|
|
||||||
|
|||||||
7
.github/workflows/update-flake.yml
vendored
7
.github/workflows/update-flake.yml
vendored
@@ -6,14 +6,13 @@ on:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
lockfile:
|
lockfile:
|
||||||
if: github.repository == 'juanfont/headscale'
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout repository
|
- name: Checkout repository
|
||||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
uses: actions/checkout@v3
|
||||||
- name: Install Nix
|
- name: Install Nix
|
||||||
uses: DeterminateSystems/nix-installer-action@21a544727d0c62386e78b4befe52d19ad12692e3 # v17
|
uses: DeterminateSystems/nix-installer-action@main
|
||||||
- name: Update flake.lock
|
- name: Update flake.lock
|
||||||
uses: DeterminateSystems/update-flake-lock@428c2b58a4b7414dabd372acb6a03dba1084d3ab # v25
|
uses: DeterminateSystems/update-flake-lock@main
|
||||||
with:
|
with:
|
||||||
pr-title: "Update flake.lock"
|
pr-title: "Update flake.lock"
|
||||||
|
|||||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,10 +1,6 @@
|
|||||||
ignored/
|
ignored/
|
||||||
tailscale/
|
tailscale/
|
||||||
.vscode/
|
.vscode/
|
||||||
.claude/
|
|
||||||
logs/
|
|
||||||
|
|
||||||
*.prof
|
|
||||||
|
|
||||||
# Binaries for programs and plugins
|
# Binaries for programs and plugins
|
||||||
*.exe
|
*.exe
|
||||||
@@ -24,9 +20,8 @@ vendor/
|
|||||||
|
|
||||||
dist/
|
dist/
|
||||||
/headscale
|
/headscale
|
||||||
|
config.json
|
||||||
config.yaml
|
config.yaml
|
||||||
config*.yaml
|
|
||||||
!config-example.yaml
|
|
||||||
derp.yaml
|
derp.yaml
|
||||||
*.hujson
|
*.hujson
|
||||||
*.key
|
*.key
|
||||||
@@ -50,7 +45,3 @@ integration_test/etc/config.dump.yaml
|
|||||||
/site
|
/site
|
||||||
|
|
||||||
__debug_bin
|
__debug_bin
|
||||||
|
|
||||||
node_modules/
|
|
||||||
package-lock.json
|
|
||||||
package.json
|
|
||||||
|
|||||||
167
.golangci.yaml
167
.golangci.yaml
@@ -1,108 +1,77 @@
|
|||||||
---
|
---
|
||||||
version: "2"
|
run:
|
||||||
|
timeout: 10m
|
||||||
|
build-tags:
|
||||||
|
- ts2019
|
||||||
|
|
||||||
|
issues:
|
||||||
|
skip-dirs:
|
||||||
|
- gen
|
||||||
linters:
|
linters:
|
||||||
default: all
|
enable-all: true
|
||||||
disable:
|
disable:
|
||||||
- cyclop
|
|
||||||
- depguard
|
- depguard
|
||||||
- dupl
|
|
||||||
- exhaustruct
|
- exhaustivestruct
|
||||||
- funcorder
|
- revive
|
||||||
- funlen
|
- lll
|
||||||
|
- interfacer
|
||||||
|
- scopelint
|
||||||
|
- maligned
|
||||||
|
- golint
|
||||||
|
- gofmt
|
||||||
- gochecknoglobals
|
- gochecknoglobals
|
||||||
- gochecknoinits
|
- gochecknoinits
|
||||||
- gocognit
|
- gocognit
|
||||||
- godox
|
- funlen
|
||||||
- interfacebloat
|
- exhaustivestruct
|
||||||
- ireturn
|
|
||||||
- lll
|
|
||||||
- maintidx
|
|
||||||
- makezero
|
|
||||||
- mnd
|
|
||||||
- musttag
|
|
||||||
- nestif
|
|
||||||
- nolintlint
|
|
||||||
- paralleltest
|
|
||||||
- revive
|
|
||||||
- tagliatelle
|
- tagliatelle
|
||||||
- testpackage
|
- godox
|
||||||
- varnamelen
|
- ireturn
|
||||||
- wrapcheck
|
- execinquery
|
||||||
- wsl
|
- exhaustruct
|
||||||
settings:
|
- nolintlint
|
||||||
forbidigo:
|
- musttag # causes issues with imported libs
|
||||||
forbid:
|
- depguard
|
||||||
# Forbid time.Sleep everywhere with context-appropriate alternatives
|
|
||||||
- pattern: 'time\.Sleep'
|
|
||||||
msg: >-
|
|
||||||
time.Sleep is forbidden.
|
|
||||||
In tests: use assert.EventuallyWithT for polling/waiting patterns.
|
|
||||||
In production code: use a backoff strategy (e.g., cenkalti/backoff) or proper synchronization primitives.
|
|
||||||
# Forbid inline string literals in zerolog field methods - use zf.* constants
|
|
||||||
- pattern: '\.(Str|Int|Int8|Int16|Int32|Int64|Uint|Uint8|Uint16|Uint32|Uint64|Float32|Float64|Bool|Dur|Time|TimeDiff|Strs|Ints|Uints|Floats|Bools|Any|Interface)\("[^"]+"'
|
|
||||||
msg: >-
|
|
||||||
Use zf.* constants for zerolog field names instead of string literals.
|
|
||||||
Import "github.com/juanfont/headscale/hscontrol/util/zlog/zf" and use
|
|
||||||
constants like zf.NodeID, zf.UserName, etc. Add new constants to
|
|
||||||
hscontrol/util/zlog/zf/fields.go if needed.
|
|
||||||
# Forbid ptr.To - use Go 1.26 new(expr) instead
|
|
||||||
- pattern: 'ptr\.To\('
|
|
||||||
msg: >-
|
|
||||||
ptr.To is forbidden. Use Go 1.26's new(expr) syntax instead.
|
|
||||||
Example: ptr.To(value) → new(value)
|
|
||||||
# Forbid tsaddr.SortPrefixes - use slices.SortFunc with netip.Prefix.Compare
|
|
||||||
- pattern: 'tsaddr\.SortPrefixes'
|
|
||||||
msg: >-
|
|
||||||
tsaddr.SortPrefixes is forbidden. Use Go 1.26's netip.Prefix.Compare instead.
|
|
||||||
Example: slices.SortFunc(prefixes, netip.Prefix.Compare)
|
|
||||||
analyze-types: true
|
|
||||||
gocritic:
|
|
||||||
disabled-checks:
|
|
||||||
- appendAssign
|
|
||||||
- ifElseChain
|
|
||||||
nlreturn:
|
|
||||||
block-size: 4
|
|
||||||
varnamelen:
|
|
||||||
ignore-names:
|
|
||||||
- err
|
|
||||||
- db
|
|
||||||
- id
|
|
||||||
- ip
|
|
||||||
- ok
|
|
||||||
- c
|
|
||||||
- tt
|
|
||||||
- tx
|
|
||||||
- rx
|
|
||||||
- sb
|
|
||||||
- wg
|
|
||||||
- pr
|
|
||||||
- p
|
|
||||||
- p2
|
|
||||||
ignore-type-assert-ok: true
|
|
||||||
ignore-map-index-ok: true
|
|
||||||
exclusions:
|
|
||||||
generated: lax
|
|
||||||
presets:
|
|
||||||
- comments
|
|
||||||
- common-false-positives
|
|
||||||
- legacy
|
|
||||||
- std-error-handling
|
|
||||||
paths:
|
|
||||||
- third_party$
|
|
||||||
- builtin$
|
|
||||||
- examples$
|
|
||||||
- gen
|
|
||||||
|
|
||||||
formatters:
|
# deprecated
|
||||||
enable:
|
- structcheck # replaced by unused
|
||||||
- gci
|
- ifshort # deprecated by the owner
|
||||||
- gofmt
|
- varcheck # replaced by unused
|
||||||
- gofumpt
|
- nosnakecase # replaced by revive
|
||||||
- goimports
|
- deadcode # replaced by unused
|
||||||
exclusions:
|
|
||||||
generated: lax
|
# We should strive to enable these:
|
||||||
paths:
|
- wrapcheck
|
||||||
- third_party$
|
- dupl
|
||||||
- builtin$
|
- makezero
|
||||||
- examples$
|
- maintidx
|
||||||
- gen
|
|
||||||
|
# Limits the methods of an interface to 10. We have more in integration tests
|
||||||
|
- interfacebloat
|
||||||
|
|
||||||
|
# We might want to enable this, but it might be a lot of work
|
||||||
|
- cyclop
|
||||||
|
- nestif
|
||||||
|
- wsl # might be incompatible with gofumpt
|
||||||
|
- testpackage
|
||||||
|
- paralleltest
|
||||||
|
|
||||||
|
linters-settings:
|
||||||
|
varnamelen:
|
||||||
|
ignore-type-assert-ok: true
|
||||||
|
ignore-map-index-ok: true
|
||||||
|
ignore-names:
|
||||||
|
- err
|
||||||
|
- db
|
||||||
|
- id
|
||||||
|
- ip
|
||||||
|
- ok
|
||||||
|
- c
|
||||||
|
- tt
|
||||||
|
|
||||||
|
gocritic:
|
||||||
|
disabled-checks:
|
||||||
|
- appendAssign
|
||||||
|
# TODO(kradalby): Remove this
|
||||||
|
- ifElseChain
|
||||||
|
|||||||
108
.goreleaser.yml
108
.goreleaser.yml
@@ -1,21 +1,15 @@
|
|||||||
---
|
---
|
||||||
version: 2
|
|
||||||
before:
|
before:
|
||||||
hooks:
|
hooks:
|
||||||
- go mod tidy -compat=1.26
|
- go mod tidy -compat=1.20
|
||||||
- go mod vendor
|
- go mod vendor
|
||||||
|
|
||||||
release:
|
release:
|
||||||
prerelease: auto
|
prerelease: auto
|
||||||
draft: true
|
|
||||||
header: |
|
|
||||||
## Upgrade
|
|
||||||
|
|
||||||
Please follow the steps outlined in the [upgrade guide](https://headscale.net/stable/setup/upgrade/) to update your existing Headscale installation.
|
|
||||||
|
|
||||||
builds:
|
builds:
|
||||||
- id: headscale
|
- id: headscale
|
||||||
main: ./cmd/headscale
|
main: ./cmd/headscale/headscale.go
|
||||||
mod_timestamp: "{{ .CommitTimestamp }}"
|
mod_timestamp: "{{ .CommitTimestamp }}"
|
||||||
env:
|
env:
|
||||||
- CGO_ENABLED=0
|
- CGO_ENABLED=0
|
||||||
@@ -23,18 +17,23 @@ builds:
|
|||||||
- darwin_amd64
|
- darwin_amd64
|
||||||
- darwin_arm64
|
- darwin_arm64
|
||||||
- freebsd_amd64
|
- freebsd_amd64
|
||||||
|
- linux_386
|
||||||
- linux_amd64
|
- linux_amd64
|
||||||
- linux_arm64
|
- linux_arm64
|
||||||
|
- linux_arm_5
|
||||||
|
- linux_arm_6
|
||||||
|
- linux_arm_7
|
||||||
flags:
|
flags:
|
||||||
- -mod=readonly
|
- -mod=readonly
|
||||||
|
ldflags:
|
||||||
|
- -s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=v{{.Version}}
|
||||||
tags:
|
tags:
|
||||||
- ts2019
|
- ts2019
|
||||||
|
|
||||||
archives:
|
archives:
|
||||||
- id: golang-cross
|
- id: golang-cross
|
||||||
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
name_template: '{{ .ProjectName }}_{{ .Version }}_{{ .Os }}_{{ .Arch }}{{ with .Arm }}v{{ . }}{{ end }}{{ with .Mips }}_{{ . }}{{ end }}{{ if not (eq .Amd64 "v1") }}{{ .Amd64 }}{{ end }}'
|
||||||
formats:
|
format: binary
|
||||||
- binary
|
|
||||||
|
|
||||||
source:
|
source:
|
||||||
enabled: true
|
enabled: true
|
||||||
@@ -53,109 +52,38 @@ nfpms:
|
|||||||
# List file contents: dpkg -c dist/headscale...deb
|
# List file contents: dpkg -c dist/headscale...deb
|
||||||
# Package metadata: dpkg --info dist/headscale....deb
|
# Package metadata: dpkg --info dist/headscale....deb
|
||||||
#
|
#
|
||||||
- ids:
|
- builds:
|
||||||
- headscale
|
- headscale
|
||||||
package_name: headscale
|
package_name: headscale
|
||||||
priority: optional
|
priority: optional
|
||||||
vendor: headscale
|
vendor: headscale
|
||||||
maintainer: Kristoffer Dalby <kristoffer@dalby.cc>
|
maintainer: Kristoffer Dalby <kristoffer@dalby.cc>
|
||||||
homepage: https://github.com/juanfont/headscale
|
homepage: https://github.com/juanfont/headscale
|
||||||
description: |-
|
license: BSD
|
||||||
Open source implementation of the Tailscale control server.
|
|
||||||
Headscale aims to implement a self-hosted, open source alternative to the
|
|
||||||
Tailscale control server. Headscale's goal is to provide self-hosters and
|
|
||||||
hobbyists with an open-source server they can use for their projects and
|
|
||||||
labs. It implements a narrow scope, a single Tailscale network (tailnet),
|
|
||||||
suitable for a personal use, or a small open-source organisation.
|
|
||||||
bindir: /usr/bin
|
bindir: /usr/bin
|
||||||
section: net
|
|
||||||
formats:
|
formats:
|
||||||
- deb
|
- deb
|
||||||
|
# - rpm
|
||||||
contents:
|
contents:
|
||||||
- src: ./config-example.yaml
|
- src: ./config-example.yaml
|
||||||
dst: /etc/headscale/config.yaml
|
dst: /etc/headscale/config.yaml
|
||||||
type: config|noreplace
|
type: config|noreplace
|
||||||
file_info:
|
file_info:
|
||||||
mode: 0644
|
mode: 0644
|
||||||
- src: ./packaging/systemd/headscale.service
|
- src: ./docs/packaging/headscale.systemd.service
|
||||||
dst: /usr/lib/systemd/system/headscale.service
|
dst: /usr/lib/systemd/system/headscale.service
|
||||||
- dst: /var/lib/headscale
|
- dst: /var/lib/headscale
|
||||||
type: dir
|
type: dir
|
||||||
- src: LICENSE
|
- dst: /var/run/headscale
|
||||||
dst: /usr/share/doc/headscale/copyright
|
type: dir
|
||||||
scripts:
|
scripts:
|
||||||
postinstall: ./packaging/deb/postinst
|
postinstall: ./docs/packaging/postinstall.sh
|
||||||
postremove: ./packaging/deb/postrm
|
postremove: ./docs/packaging/postremove.sh
|
||||||
preremove: ./packaging/deb/prerm
|
|
||||||
deb:
|
|
||||||
lintian_overrides:
|
|
||||||
- no-changelog # Our CHANGELOG.md uses a different formatting
|
|
||||||
- no-manual-page
|
|
||||||
- statically-linked-binary
|
|
||||||
|
|
||||||
kos:
|
|
||||||
- id: ghcr
|
|
||||||
repositories:
|
|
||||||
- ghcr.io/juanfont/headscale
|
|
||||||
- headscale/headscale
|
|
||||||
|
|
||||||
# bare tells KO to only use the repository
|
|
||||||
# for tagging and naming the container.
|
|
||||||
bare: true
|
|
||||||
base_image: gcr.io/distroless/base-debian13
|
|
||||||
build: headscale
|
|
||||||
main: ./cmd/headscale
|
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
platforms:
|
|
||||||
- linux/amd64
|
|
||||||
- linux/arm64
|
|
||||||
tags:
|
|
||||||
- "{{ if not .Prerelease }}latest{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}{{ .Major }}.{{ .Minor }}.{{ .Patch }}{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}{{ .Major }}.{{ .Minor }}{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}{{ .Major }}{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}v{{ .Major }}.{{ .Minor }}.{{ .Patch }}{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}v{{ .Major }}.{{ .Minor }}{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}v{{ .Major }}{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}stable{{ else }}unstable{{ end }}"
|
|
||||||
- "{{ .Tag }}"
|
|
||||||
- '{{ trimprefix .Tag "v" }}'
|
|
||||||
- "sha-{{ .ShortCommit }}"
|
|
||||||
creation_time: "{{.CommitTimestamp}}"
|
|
||||||
ko_data_creation_time: "{{.CommitTimestamp}}"
|
|
||||||
|
|
||||||
- id: ghcr-debug
|
|
||||||
repositories:
|
|
||||||
- ghcr.io/juanfont/headscale
|
|
||||||
- headscale/headscale
|
|
||||||
|
|
||||||
bare: true
|
|
||||||
base_image: gcr.io/distroless/base-debian13:debug
|
|
||||||
build: headscale
|
|
||||||
main: ./cmd/headscale
|
|
||||||
env:
|
|
||||||
- CGO_ENABLED=0
|
|
||||||
platforms:
|
|
||||||
- linux/amd64
|
|
||||||
- linux/arm64
|
|
||||||
tags:
|
|
||||||
- "{{ if not .Prerelease }}latest-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}{{ .Major }}.{{ .Minor }}.{{ .Patch }}-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}{{ .Major }}.{{ .Minor }}-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}{{ .Major }}-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}v{{ .Major }}.{{ .Minor }}.{{ .Patch }}-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}v{{ .Major }}.{{ .Minor }}-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}v{{ .Major }}-debug{{ end }}"
|
|
||||||
- "{{ if not .Prerelease }}stable-debug{{ else }}unstable-debug{{ end }}"
|
|
||||||
- "{{ .Tag }}-debug"
|
|
||||||
- '{{ trimprefix .Tag "v" }}-debug'
|
|
||||||
- "sha-{{ .ShortCommit }}-debug"
|
|
||||||
|
|
||||||
checksum:
|
checksum:
|
||||||
name_template: "checksums.txt"
|
name_template: "checksums.txt"
|
||||||
snapshot:
|
snapshot:
|
||||||
version_template: "{{ .Tag }}-next"
|
name_template: "{{ .Tag }}-next"
|
||||||
changelog:
|
changelog:
|
||||||
sort: asc
|
sort: asc
|
||||||
filters:
|
filters:
|
||||||
|
|||||||
34
.mcp.json
34
.mcp.json
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"claude-code-mcp": {
|
|
||||||
"type": "stdio",
|
|
||||||
"command": "npx",
|
|
||||||
"args": ["-y", "@steipete/claude-code-mcp@latest"],
|
|
||||||
"env": {}
|
|
||||||
},
|
|
||||||
"sequential-thinking": {
|
|
||||||
"type": "stdio",
|
|
||||||
"command": "npx",
|
|
||||||
"args": ["-y", "@modelcontextprotocol/server-sequential-thinking"],
|
|
||||||
"env": {}
|
|
||||||
},
|
|
||||||
"nixos": {
|
|
||||||
"type": "stdio",
|
|
||||||
"command": "uvx",
|
|
||||||
"args": ["mcp-nixos"],
|
|
||||||
"env": {}
|
|
||||||
},
|
|
||||||
"context7": {
|
|
||||||
"type": "stdio",
|
|
||||||
"command": "npx",
|
|
||||||
"args": ["-y", "@upstash/context7-mcp"],
|
|
||||||
"env": {}
|
|
||||||
},
|
|
||||||
"git": {
|
|
||||||
"type": "stdio",
|
|
||||||
"command": "npx",
|
|
||||||
"args": ["-y", "@cyanheads/git-mcp-server"],
|
|
||||||
"env": {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
# prek/pre-commit configuration for headscale
|
|
||||||
# See: https://prek.j178.dev/quickstart/
|
|
||||||
# See: https://prek.j178.dev/builtin/
|
|
||||||
|
|
||||||
# Global exclusions - ignore generated code
|
|
||||||
exclude: ^gen/
|
|
||||||
|
|
||||||
repos:
|
|
||||||
# Built-in hooks from pre-commit/pre-commit-hooks
|
|
||||||
# prek will use fast-path optimized versions automatically
|
|
||||||
# See: https://prek.j178.dev/builtin/
|
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
||||||
rev: v6.0.0
|
|
||||||
hooks:
|
|
||||||
- id: check-added-large-files
|
|
||||||
- id: check-case-conflict
|
|
||||||
- id: check-executables-have-shebangs
|
|
||||||
- id: check-json
|
|
||||||
- id: check-merge-conflict
|
|
||||||
- id: check-symlinks
|
|
||||||
- id: check-toml
|
|
||||||
- id: check-xml
|
|
||||||
- id: check-yaml
|
|
||||||
- id: detect-private-key
|
|
||||||
- id: end-of-file-fixer
|
|
||||||
- id: fix-byte-order-marker
|
|
||||||
- id: mixed-line-ending
|
|
||||||
- id: trailing-whitespace
|
|
||||||
|
|
||||||
# Local hooks for project-specific tooling
|
|
||||||
- repo: local
|
|
||||||
hooks:
|
|
||||||
# nixpkgs-fmt for Nix files
|
|
||||||
- id: nixpkgs-fmt
|
|
||||||
name: nixpkgs-fmt
|
|
||||||
entry: nixpkgs-fmt
|
|
||||||
language: system
|
|
||||||
files: \.nix$
|
|
||||||
|
|
||||||
# Prettier for formatting
|
|
||||||
- id: prettier
|
|
||||||
name: prettier
|
|
||||||
entry: prettier --write --list-different
|
|
||||||
language: system
|
|
||||||
exclude: ^docs/
|
|
||||||
types_or: [javascript, jsx, ts, tsx, yaml, json, toml, html, css, scss, sass, markdown]
|
|
||||||
|
|
||||||
# golangci-lint for Go code quality
|
|
||||||
- id: golangci-lint
|
|
||||||
name: golangci-lint
|
|
||||||
entry: nix develop --command -- golangci-lint run --new-from-rev=HEAD~1 --timeout=5m --fix
|
|
||||||
language: system
|
|
||||||
types: [go]
|
|
||||||
pass_filenames: false
|
|
||||||
@@ -1,5 +1 @@
|
|||||||
.github/workflows/test-integration-v2*
|
.github/workflows/test-integration-v2*
|
||||||
docs/about/features.md
|
|
||||||
docs/ref/api.md
|
|
||||||
docs/ref/configuration.md
|
|
||||||
docs/ref/oidc.md
|
|
||||||
|
|||||||
1033
CHANGELOG.md
1033
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
@@ -62,7 +62,7 @@ event.
|
|||||||
|
|
||||||
Instances of abusive, harassing, or otherwise unacceptable behavior
|
Instances of abusive, harassing, or otherwise unacceptable behavior
|
||||||
may be reported to the community leaders responsible for enforcement
|
may be reported to the community leaders responsible for enforcement
|
||||||
on our [Discord server](https://discord.gg/c84AZQhmpx). All complaints
|
at our Discord channel. All complaints
|
||||||
will be reviewed and investigated promptly and fairly.
|
will be reviewed and investigated promptly and fairly.
|
||||||
|
|
||||||
All community leaders are obligated to respect the privacy and
|
All community leaders are obligated to respect the privacy and
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
# Contributing
|
|
||||||
|
|
||||||
Headscale is "Open Source, acknowledged contribution", this means that any contribution will have to be discussed with the maintainers before being added to the project.
|
|
||||||
This model has been chosen to reduce the risk of burnout by limiting the maintenance overhead of reviewing and validating third-party code.
|
|
||||||
|
|
||||||
## Why do we have this model?
|
|
||||||
|
|
||||||
Headscale has a small maintainer team that tries to balance working on the project, fixing bugs and reviewing contributions.
|
|
||||||
|
|
||||||
When we work on issues ourselves, we develop first hand knowledge of the code and it makes it possible for us to maintain and own the code as the project develops.
|
|
||||||
|
|
||||||
Code contributions are seen as a positive thing. People enjoy and engage with our project, but it also comes with some challenges; we have to understand the code, we have to understand the feature, we might have to become familiar with external libraries or services and we think about security implications. All those steps are required during the reviewing process. After the code has been merged, the feature has to be maintained. Any changes reliant on external services must be updated and expanded accordingly.
|
|
||||||
|
|
||||||
The review and day-1 maintenance adds a significant burden on the maintainers. Often we hope that the contributor will help out, but we found that most of the time, they disappear after their new feature was added.
|
|
||||||
|
|
||||||
This means that when someone contributes, we are mostly happy about it, but we do have to run it through a series of checks to establish if we actually can maintain this feature.
|
|
||||||
|
|
||||||
## What do we require?
|
|
||||||
|
|
||||||
A general description is provided here and an explicit list is provided in our pull request template.
|
|
||||||
|
|
||||||
All new features have to start out with a design document, which should be discussed on the issue tracker (not discord). It should include a use case for the feature, how it can be implemented, who will implement it and a plan for maintaining it.
|
|
||||||
|
|
||||||
All features have to be end-to-end tested (integration tests) and have good unit test coverage to ensure that they work as expected. This will also ensure that the feature continues to work as expected over time. If a change cannot be tested, a strong case for why this is not possible needs to be presented.
|
|
||||||
|
|
||||||
The contributor should help to maintain the feature over time. In case the feature is not maintained probably, the maintainers reserve themselves the right to remove features they redeem as unmaintainable. This should help to improve the quality of the software and keep it in a maintainable state.
|
|
||||||
|
|
||||||
## Bug fixes
|
|
||||||
|
|
||||||
Headscale is open to code contributions for bug fixes without discussion.
|
|
||||||
|
|
||||||
## Documentation
|
|
||||||
|
|
||||||
If you find mistakes in the documentation, please submit a fix to the documentation.
|
|
||||||
30
Dockerfile
Normal file
30
Dockerfile
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Builder image
|
||||||
|
FROM docker.io/golang:1.21-bookworm AS build
|
||||||
|
ARG VERSION=dev
|
||||||
|
ENV GOPATH /go
|
||||||
|
WORKDIR /go/src/headscale
|
||||||
|
|
||||||
|
COPY go.mod go.sum /go/src/headscale/
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale
|
||||||
|
RUN strip /go/bin/headscale
|
||||||
|
RUN test -e /go/bin/headscale
|
||||||
|
|
||||||
|
# Production image
|
||||||
|
FROM docker.io/debian:bookworm-slim
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install -y ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& apt-get clean
|
||||||
|
|
||||||
|
COPY --from=build /go/bin/headscale /bin/headscale
|
||||||
|
ENV TZ UTC
|
||||||
|
|
||||||
|
RUN mkdir -p /var/run/headscale
|
||||||
|
|
||||||
|
EXPOSE 8080/tcp
|
||||||
|
CMD ["headscale"]
|
||||||
30
Dockerfile.debug
Normal file
30
Dockerfile.debug
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# Builder image
|
||||||
|
FROM docker.io/golang:1.21-bookworm AS build
|
||||||
|
ARG VERSION=dev
|
||||||
|
ENV GOPATH /go
|
||||||
|
WORKDIR /go/src/headscale
|
||||||
|
|
||||||
|
COPY go.mod go.sum /go/src/headscale/
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go install -ldflags="-s -w -X github.com/juanfont/headscale/cmd/headscale/cli.Version=$VERSION" -a ./cmd/headscale
|
||||||
|
RUN test -e /go/bin/headscale
|
||||||
|
|
||||||
|
# Debug image
|
||||||
|
FROM docker.io/golang:1.21-bookworm
|
||||||
|
|
||||||
|
COPY --from=build /go/bin/headscale /bin/headscale
|
||||||
|
ENV TZ UTC
|
||||||
|
|
||||||
|
RUN apt-get update \
|
||||||
|
&& apt-get install --no-install-recommends --yes less jq \
|
||||||
|
&& rm -rf /var/lib/apt/lists/* \
|
||||||
|
&& apt-get clean
|
||||||
|
RUN mkdir -p /var/run/headscale
|
||||||
|
|
||||||
|
# Need to reset the entrypoint or everything will run as a busybox script
|
||||||
|
ENTRYPOINT []
|
||||||
|
EXPOSE 8080/tcp
|
||||||
|
CMD ["headscale"]
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
# For testing purposes only
|
|
||||||
|
|
||||||
FROM golang:1.26.0-alpine AS build-env
|
|
||||||
|
|
||||||
WORKDIR /go/src
|
|
||||||
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
ARG VERSION_BRANCH=main
|
|
||||||
RUN git clone https://github.com/tailscale/tailscale.git --branch=$VERSION_BRANCH --depth=1
|
|
||||||
WORKDIR /go/src/tailscale
|
|
||||||
|
|
||||||
ARG TARGETARCH
|
|
||||||
RUN GOARCH=$TARGETARCH go install -v ./cmd/derper
|
|
||||||
|
|
||||||
FROM alpine:3.22
|
|
||||||
RUN apk add --no-cache ca-certificates iptables iproute2 ip6tables curl
|
|
||||||
|
|
||||||
COPY --from=build-env /go/bin/* /usr/local/bin/
|
|
||||||
ENTRYPOINT [ "/usr/local/bin/derper" ]
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
# This Dockerfile and the images produced are for testing headscale,
|
|
||||||
# and are in no way endorsed by Headscale's maintainers as an
|
|
||||||
# official nor supported release or distribution.
|
|
||||||
|
|
||||||
FROM docker.io/golang:1.26.0-trixie AS builder
|
|
||||||
ARG VERSION=dev
|
|
||||||
ENV GOPATH /go
|
|
||||||
WORKDIR /go/src/headscale
|
|
||||||
|
|
||||||
# Install delve debugger first - rarely changes, good cache candidate
|
|
||||||
RUN go install github.com/go-delve/delve/cmd/dlv@latest
|
|
||||||
|
|
||||||
# Download dependencies - only invalidated when go.mod/go.sum change
|
|
||||||
COPY go.mod go.sum /go/src/headscale/
|
|
||||||
RUN go mod download
|
|
||||||
|
|
||||||
# Copy source and build - invalidated on any source change
|
|
||||||
COPY . .
|
|
||||||
|
|
||||||
# Build debug binary with debug symbols for delve
|
|
||||||
RUN CGO_ENABLED=0 GOOS=linux go build -gcflags="all=-N -l" -o /go/bin/headscale ./cmd/headscale
|
|
||||||
|
|
||||||
# Runtime stage
|
|
||||||
FROM debian:trixie-slim
|
|
||||||
|
|
||||||
RUN apt-get --update install --no-install-recommends --yes \
|
|
||||||
bash ca-certificates curl dnsutils findutils iproute2 jq less procps python3 sqlite3 \
|
|
||||||
&& apt-get dist-clean
|
|
||||||
|
|
||||||
RUN mkdir -p /var/run/headscale
|
|
||||||
|
|
||||||
# Copy binaries from builder
|
|
||||||
COPY --from=builder /go/bin/headscale /usr/local/bin/headscale
|
|
||||||
COPY --from=builder /go/bin/dlv /usr/local/bin/dlv
|
|
||||||
|
|
||||||
# Copy source code for delve source-level debugging
|
|
||||||
COPY --from=builder /go/src/headscale /go/src/headscale
|
|
||||||
|
|
||||||
WORKDIR /go/src/headscale
|
|
||||||
|
|
||||||
# Need to reset the entrypoint or everything will run as a busybox script
|
|
||||||
ENTRYPOINT []
|
|
||||||
EXPOSE 8080/tcp 40000/tcp
|
|
||||||
CMD ["dlv", "--listen=0.0.0.0:40000", "--headless=true", "--api-version=2", "--accept-multiclient", "exec", "/usr/local/bin/headscale", "--"]
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Minimal CI image - expects pre-built headscale binary in build context
|
|
||||||
# For local development with delve debugging, use Dockerfile.integration instead
|
|
||||||
|
|
||||||
FROM debian:trixie-slim
|
|
||||||
|
|
||||||
RUN apt-get --update install --no-install-recommends --yes \
|
|
||||||
bash ca-certificates curl dnsutils findutils iproute2 jq less procps python3 sqlite3 \
|
|
||||||
&& apt-get dist-clean
|
|
||||||
|
|
||||||
RUN mkdir -p /var/run/headscale
|
|
||||||
|
|
||||||
# Copy pre-built headscale binary from build context
|
|
||||||
COPY headscale /usr/local/bin/headscale
|
|
||||||
|
|
||||||
ENTRYPOINT []
|
|
||||||
EXPOSE 8080/tcp
|
|
||||||
CMD ["/usr/local/bin/headscale"]
|
|
||||||
@@ -1,47 +1,17 @@
|
|||||||
# Copyright (c) Tailscale Inc & AUTHORS
|
FROM golang:latest
|
||||||
# SPDX-License-Identifier: BSD-3-Clause
|
|
||||||
|
|
||||||
# This Dockerfile is more or less lifted from tailscale/tailscale
|
RUN apt-get update \
|
||||||
# to ensure a similar build process when testing the HEAD of tailscale.
|
&& apt-get install -y dnsutils git iptables ssh ca-certificates \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
FROM golang:1.26.0-alpine AS build-env
|
RUN useradd --shell=/bin/bash --create-home ssh-it-user
|
||||||
|
|
||||||
WORKDIR /go/src
|
|
||||||
|
|
||||||
RUN apk add --no-cache git
|
|
||||||
|
|
||||||
# Replace `RUN git...` with `COPY` and a local checked out version of Tailscale in `./tailscale`
|
|
||||||
# to test specific commits of the Tailscale client. This is useful when trying to find out why
|
|
||||||
# something specific broke between two versions of Tailscale with for example `git bisect`.
|
|
||||||
# COPY ./tailscale .
|
|
||||||
RUN git clone https://github.com/tailscale/tailscale.git
|
RUN git clone https://github.com/tailscale/tailscale.git
|
||||||
|
|
||||||
WORKDIR /go/src/tailscale
|
WORKDIR /go/tailscale
|
||||||
|
|
||||||
|
RUN git checkout main \
|
||||||
# see build_docker.sh
|
&& sh build_dist.sh tailscale.com/cmd/tailscale \
|
||||||
ARG VERSION_LONG=""
|
&& sh build_dist.sh tailscale.com/cmd/tailscaled \
|
||||||
ENV VERSION_LONG=$VERSION_LONG
|
&& cp tailscale /usr/local/bin/ \
|
||||||
ARG VERSION_SHORT=""
|
&& cp tailscaled /usr/local/bin/
|
||||||
ENV VERSION_SHORT=$VERSION_SHORT
|
|
||||||
ARG VERSION_GIT_HASH=""
|
|
||||||
ENV VERSION_GIT_HASH=$VERSION_GIT_HASH
|
|
||||||
ARG TARGETARCH
|
|
||||||
|
|
||||||
ARG BUILD_TAGS=""
|
|
||||||
|
|
||||||
RUN GOARCH=$TARGETARCH go install -tags="${BUILD_TAGS}" -ldflags="\
|
|
||||||
-X tailscale.com/version.longStamp=$VERSION_LONG \
|
|
||||||
-X tailscale.com/version.shortStamp=$VERSION_SHORT \
|
|
||||||
-X tailscale.com/version.gitCommitStamp=$VERSION_GIT_HASH" \
|
|
||||||
-v ./cmd/tailscale ./cmd/tailscaled ./cmd/containerboot
|
|
||||||
|
|
||||||
FROM alpine:3.22
|
|
||||||
# Upstream: ca-certificates ip6tables iptables iproute2
|
|
||||||
# Tests: curl python3 (traceroute via BusyBox)
|
|
||||||
RUN apk add --no-cache ca-certificates curl ip6tables iptables iproute2 python3
|
|
||||||
|
|
||||||
COPY --from=build-env /go/bin/* /usr/local/bin/
|
|
||||||
# For compat with the previous run.sh, although ideally you should be
|
|
||||||
# using build_docker.sh which sets an entrypoint for the image.
|
|
||||||
RUN mkdir /tailscale && ln -s /usr/local/bin/containerboot /tailscale/run.sh
|
|
||||||
|
|||||||
151
Makefile
151
Makefile
@@ -1,128 +1,53 @@
|
|||||||
# Headscale Makefile
|
# Calculate version
|
||||||
# Modern Makefile following best practices
|
version ?= $(shell git describe --always --tags --dirty)
|
||||||
|
|
||||||
# Version calculation
|
rwildcard=$(foreach d,$(wildcard $1*),$(call rwildcard,$d/,$2) $(filter $(subst *,%,$2),$d))
|
||||||
VERSION ?= $(shell git describe --always --tags --dirty)
|
|
||||||
|
|
||||||
# Build configuration
|
# Determine if OS supports pie
|
||||||
GOOS ?= $(shell uname | tr '[:upper:]' '[:lower:]')
|
GOOS ?= $(shell uname | tr '[:upper:]' '[:lower:]')
|
||||||
ifeq ($(filter $(GOOS), openbsd netbsd solaris plan9), )
|
ifeq ($(filter $(GOOS), openbsd netbsd soloaris plan9), )
|
||||||
PIE_FLAGS = -buildmode=pie
|
pieflags = -buildmode=pie
|
||||||
|
else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Tool availability check with nix warning
|
# GO_SOURCES = $(wildcard *.go)
|
||||||
define check_tool
|
# PROTO_SOURCES = $(wildcard **/*.proto)
|
||||||
@command -v $(1) >/dev/null 2>&1 || { \
|
GO_SOURCES = $(call rwildcard,,*.go)
|
||||||
echo "Warning: $(1) not found. Run 'nix develop' to ensure all dependencies are available."; \
|
PROTO_SOURCES = $(call rwildcard,,*.proto)
|
||||||
exit 1; \
|
|
||||||
}
|
|
||||||
endef
|
|
||||||
|
|
||||||
# Source file collections using shell find for better performance
|
|
||||||
GO_SOURCES := $(shell find . -name '*.go' -not -path './gen/*' -not -path './vendor/*')
|
|
||||||
PROTO_SOURCES := $(shell find . -name '*.proto' -not -path './gen/*' -not -path './vendor/*')
|
|
||||||
DOC_SOURCES := $(shell find . \( -name '*.md' -o -name '*.yaml' -o -name '*.yml' -o -name '*.ts' -o -name '*.js' -o -name '*.html' -o -name '*.css' -o -name '*.scss' -o -name '*.sass' \) -not -path './gen/*' -not -path './vendor/*' -not -path './node_modules/*')
|
|
||||||
|
|
||||||
# Default target
|
|
||||||
.PHONY: all
|
|
||||||
all: lint test build
|
|
||||||
|
|
||||||
# Dependency checking
|
|
||||||
.PHONY: check-deps
|
|
||||||
check-deps:
|
|
||||||
$(call check_tool,go)
|
|
||||||
$(call check_tool,golangci-lint)
|
|
||||||
$(call check_tool,gofumpt)
|
|
||||||
$(call check_tool,prettier)
|
|
||||||
$(call check_tool,clang-format)
|
|
||||||
$(call check_tool,buf)
|
|
||||||
|
|
||||||
# Build targets
|
|
||||||
.PHONY: build
|
|
||||||
build: check-deps $(GO_SOURCES) go.mod go.sum
|
|
||||||
@echo "Building headscale..."
|
|
||||||
go build $(PIE_FLAGS) -ldflags "-X main.version=$(VERSION)" -o headscale ./cmd/headscale
|
|
||||||
|
|
||||||
# Test targets
|
|
||||||
.PHONY: test
|
|
||||||
test: check-deps $(GO_SOURCES) go.mod go.sum
|
|
||||||
@echo "Running Go tests..."
|
|
||||||
go test -race ./...
|
|
||||||
|
|
||||||
|
|
||||||
# Formatting targets
|
build:
|
||||||
.PHONY: fmt
|
nix build
|
||||||
fmt: fmt-go fmt-prettier fmt-proto
|
|
||||||
|
|
||||||
.PHONY: fmt-go
|
dev: lint test build
|
||||||
fmt-go: check-deps $(GO_SOURCES)
|
|
||||||
@echo "Formatting Go code..."
|
|
||||||
gofumpt -l -w .
|
|
||||||
golangci-lint run --fix
|
|
||||||
|
|
||||||
.PHONY: fmt-prettier
|
test:
|
||||||
fmt-prettier: check-deps $(DOC_SOURCES)
|
gotestsum -- -short -coverprofile=coverage.out ./...
|
||||||
@echo "Formatting documentation and config files..."
|
|
||||||
prettier --write '**/*.{ts,js,md,yaml,yml,sass,css,scss,html}'
|
|
||||||
|
|
||||||
.PHONY: fmt-proto
|
test_integration:
|
||||||
fmt-proto: check-deps $(PROTO_SOURCES)
|
docker run \
|
||||||
@echo "Formatting Protocol Buffer files..."
|
-t --rm \
|
||||||
clang-format -i $(PROTO_SOURCES)
|
-v ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
-v $$PWD:$$PWD -w $$PWD/integration \
|
||||||
|
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- -failfast ./... -timeout 120m -parallel 8
|
||||||
|
|
||||||
# Linting targets
|
lint:
|
||||||
.PHONY: lint
|
golangci-lint run --fix --timeout 10m
|
||||||
lint: lint-go lint-proto
|
|
||||||
|
|
||||||
.PHONY: lint-go
|
fmt:
|
||||||
lint-go: check-deps $(GO_SOURCES) go.mod go.sum
|
prettier --write '**/**.{ts,js,md,yaml,yml,sass,css,scss,html}'
|
||||||
@echo "Linting Go code..."
|
golines --max-len=88 --base-formatter=gofumpt -w $(GO_SOURCES)
|
||||||
golangci-lint run --timeout 10m
|
clang-format -style="{BasedOnStyle: Google, IndentWidth: 4, AlignConsecutiveDeclarations: true, AlignConsecutiveAssignments: true, ColumnLimit: 0}" -i $(PROTO_SOURCES)
|
||||||
|
|
||||||
.PHONY: lint-proto
|
proto-lint:
|
||||||
lint-proto: check-deps $(PROTO_SOURCES)
|
cd proto/ && go run github.com/bufbuild/buf/cmd/buf lint
|
||||||
@echo "Linting Protocol Buffer files..."
|
|
||||||
cd proto/ && buf lint
|
|
||||||
|
|
||||||
# Code generation
|
compress: build
|
||||||
.PHONY: generate
|
upx --brute headscale
|
||||||
generate: check-deps
|
|
||||||
@echo "Generating code..."
|
|
||||||
go generate ./...
|
|
||||||
|
|
||||||
# Clean targets
|
generate:
|
||||||
.PHONY: clean
|
rm -rf gen
|
||||||
clean:
|
buf generate proto
|
||||||
rm -rf headscale gen
|
|
||||||
|
|
||||||
# Development workflow
|
|
||||||
.PHONY: dev
|
|
||||||
dev: fmt lint test build
|
|
||||||
|
|
||||||
# Help target
|
|
||||||
.PHONY: help
|
|
||||||
help:
|
|
||||||
@echo "Headscale Development Makefile"
|
|
||||||
@echo ""
|
|
||||||
@echo "Main targets:"
|
|
||||||
@echo " all - Run lint, test, and build (default)"
|
|
||||||
@echo " build - Build headscale binary"
|
|
||||||
@echo " test - Run Go tests"
|
|
||||||
@echo " fmt - Format all code (Go, docs, proto)"
|
|
||||||
@echo " lint - Lint all code (Go, proto)"
|
|
||||||
@echo " generate - Generate code from Protocol Buffers"
|
|
||||||
@echo " dev - Full development workflow (fmt + lint + test + build)"
|
|
||||||
@echo " clean - Clean build artifacts"
|
|
||||||
@echo ""
|
|
||||||
@echo "Specific targets:"
|
|
||||||
@echo " fmt-go - Format Go code only"
|
|
||||||
@echo " fmt-prettier - Format documentation only"
|
|
||||||
@echo " fmt-proto - Format Protocol Buffer files only"
|
|
||||||
@echo " lint-go - Lint Go code only"
|
|
||||||
@echo " lint-proto - Lint Protocol Buffer files only"
|
|
||||||
@echo ""
|
|
||||||
@echo "Dependencies:"
|
|
||||||
@echo " check-deps - Verify required tools are available"
|
|
||||||
@echo ""
|
|
||||||
@echo "Note: If not running in a nix shell, ensure dependencies are available:"
|
|
||||||
@echo " nix develop"
|
|
||||||
|
|||||||
173
cmd/gh-action-integration-generator/main.go
Normal file
173
cmd/gh-action-integration-generator/main.go
Normal file
@@ -0,0 +1,173 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
//go:generate go run ./main.go
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"path"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
githubWorkflowPath = "../../.github/workflows/"
|
||||||
|
jobFileNameTemplate = `test-integration-v2-%s.yaml`
|
||||||
|
jobTemplate = template.Must(
|
||||||
|
template.New("jobTemplate").
|
||||||
|
Parse(`# DO NOT EDIT, generated with cmd/gh-action-integration-generator/main.go
|
||||||
|
# To regenerate, run "go generate" in cmd/gh-action-integration-generator/
|
||||||
|
|
||||||
|
name: Integration Test v2 - {{.Name}}
|
||||||
|
|
||||||
|
on: [pull_request]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: {{ "${{ github.workflow }}-$${{ github.head_ref || github.run_id }}" }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
{{.Name}}:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
- uses: DeterminateSystems/nix-installer-action@main
|
||||||
|
- uses: DeterminateSystems/magic-nix-cache-action@main
|
||||||
|
- uses: satackey/action-docker-layer-caching@main
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v34
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
*.nix
|
||||||
|
go.*
|
||||||
|
**/*.go
|
||||||
|
integration_test/
|
||||||
|
config-example.yaml
|
||||||
|
|
||||||
|
- name: Run {{.Name}}
|
||||||
|
uses: Wandalen/wretry.action@master
|
||||||
|
if: steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
attempt_limit: 5
|
||||||
|
command: |
|
||||||
|
nix develop --command -- docker run \
|
||||||
|
--tty --rm \
|
||||||
|
--volume ~/.cache/hs-integration-go:/go \
|
||||||
|
--name headscale-test-suite \
|
||||||
|
--volume $PWD:$PWD -w $PWD/integration \
|
||||||
|
--volume /var/run/docker.sock:/var/run/docker.sock \
|
||||||
|
--volume $PWD/control_logs:/tmp/control \
|
||||||
|
golang:1 \
|
||||||
|
go run gotest.tools/gotestsum@latest -- ./... \
|
||||||
|
-failfast \
|
||||||
|
-timeout 120m \
|
||||||
|
-parallel 1 \
|
||||||
|
-run "^{{.Name}}$"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: logs
|
||||||
|
path: "control_logs/*.log"
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v3
|
||||||
|
if: always() && steps.changed-files.outputs.any_changed == 'true'
|
||||||
|
with:
|
||||||
|
name: pprof
|
||||||
|
path: "control_logs/*.pprof.tar"
|
||||||
|
`),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
const workflowFilePerm = 0o600
|
||||||
|
|
||||||
|
func removeTests() {
|
||||||
|
glob := fmt.Sprintf(jobFileNameTemplate, "*")
|
||||||
|
|
||||||
|
files, err := filepath.Glob(filepath.Join(githubWorkflowPath, glob))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to find test files")
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, file := range files {
|
||||||
|
err := os.Remove(file)
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("failed to remove: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func findTests() []string {
|
||||||
|
rgBin, err := exec.LookPath("rg")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to find rg (ripgrep) binary")
|
||||||
|
}
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"--regexp", "func (Test.+)\\(.*",
|
||||||
|
"../../integration/",
|
||||||
|
"--replace", "$1",
|
||||||
|
"--sort", "path",
|
||||||
|
"--no-line-number",
|
||||||
|
"--no-filename",
|
||||||
|
"--no-heading",
|
||||||
|
}
|
||||||
|
|
||||||
|
log.Printf("executing: %s %s", rgBin, strings.Join(args, " "))
|
||||||
|
|
||||||
|
ripgrep := exec.Command(
|
||||||
|
rgBin,
|
||||||
|
args...,
|
||||||
|
)
|
||||||
|
|
||||||
|
result, err := ripgrep.CombinedOutput()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("out: %s", result)
|
||||||
|
log.Fatalf("failed to run ripgrep: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := strings.Split(string(result), "\n")
|
||||||
|
tests = tests[:len(tests)-1]
|
||||||
|
|
||||||
|
return tests
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
type testConfig struct {
|
||||||
|
Name string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := findTests()
|
||||||
|
|
||||||
|
removeTests()
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
log.Printf("generating workflow for %s", test)
|
||||||
|
|
||||||
|
var content bytes.Buffer
|
||||||
|
|
||||||
|
if err := jobTemplate.Execute(&content, testConfig{
|
||||||
|
Name: test,
|
||||||
|
}); err != nil {
|
||||||
|
log.Fatalf("failed to render template: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
testPath := path.Join(githubWorkflowPath, fmt.Sprintf(jobFileNameTemplate, test))
|
||||||
|
|
||||||
|
err := os.WriteFile(testPath, content.Bytes(), workflowFilePerm)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("failed to write github job: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,18 +1,21 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
"github.com/juanfont/headscale/hscontrol/util"
|
"github.com/juanfont/headscale/hscontrol/util"
|
||||||
|
"github.com/prometheus/common/model"
|
||||||
"github.com/pterm/pterm"
|
"github.com/pterm/pterm"
|
||||||
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"google.golang.org/protobuf/types/known/timestamppb"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
// DefaultAPIKeyExpiry is 90 days.
|
// 90 days.
|
||||||
DefaultAPIKeyExpiry = "90d"
|
DefaultAPIKeyExpiry = "90d"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -26,12 +29,11 @@ func init() {
|
|||||||
apiKeysCmd.AddCommand(createAPIKeyCmd)
|
apiKeysCmd.AddCommand(createAPIKeyCmd)
|
||||||
|
|
||||||
expireAPIKeyCmd.Flags().StringP("prefix", "p", "", "ApiKey prefix")
|
expireAPIKeyCmd.Flags().StringP("prefix", "p", "", "ApiKey prefix")
|
||||||
expireAPIKeyCmd.Flags().Uint64P("id", "i", 0, "ApiKey ID")
|
err := expireAPIKeyCmd.MarkFlagRequired("prefix")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("")
|
||||||
|
}
|
||||||
apiKeysCmd.AddCommand(expireAPIKeyCmd)
|
apiKeysCmd.AddCommand(expireAPIKeyCmd)
|
||||||
|
|
||||||
deleteAPIKeyCmd.Flags().StringP("prefix", "p", "", "ApiKey prefix")
|
|
||||||
deleteAPIKeyCmd.Flags().Uint64P("id", "i", 0, "ApiKey ID")
|
|
||||||
apiKeysCmd.AddCommand(deleteAPIKeyCmd)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var apiKeysCmd = &cobra.Command{
|
var apiKeysCmd = &cobra.Command{
|
||||||
@@ -44,35 +46,61 @@ var listAPIKeys = &cobra.Command{
|
|||||||
Use: "list",
|
Use: "list",
|
||||||
Short: "List the Api keys for headscale",
|
Short: "List the Api keys for headscale",
|
||||||
Aliases: []string{"ls", "show"},
|
Aliases: []string{"ls", "show"},
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
response, err := client.ListApiKeys(ctx, &v1.ListApiKeysRequest{})
|
output, _ := cmd.Flags().GetString("output")
|
||||||
|
|
||||||
|
ctx, client, conn, cancel := getHeadscaleCLIClient()
|
||||||
|
defer cancel()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
request := &v1.ListApiKeysRequest{}
|
||||||
|
|
||||||
|
response, err := client.ListApiKeys(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("listing api keys: %w", err)
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Error getting the list of keys: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return printListOutput(cmd, response.GetApiKeys(), func() error {
|
if output != "" {
|
||||||
tableData := pterm.TableData{
|
SuccessOutput(response.GetApiKeys(), "", output)
|
||||||
{"ID", "Prefix", "Expiration", "Created"},
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tableData := pterm.TableData{
|
||||||
|
{"ID", "Prefix", "Expiration", "Created"},
|
||||||
|
}
|
||||||
|
for _, key := range response.GetApiKeys() {
|
||||||
|
expiration := "-"
|
||||||
|
|
||||||
|
if key.GetExpiration() != nil {
|
||||||
|
expiration = ColourTime(key.GetExpiration().AsTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, key := range response.GetApiKeys() {
|
tableData = append(tableData, []string{
|
||||||
expiration := "-"
|
strconv.FormatUint(key.GetId(), util.Base10),
|
||||||
|
key.GetPrefix(),
|
||||||
|
expiration,
|
||||||
|
key.GetCreatedAt().AsTime().Format(HeadscaleDateTimeFormat),
|
||||||
|
})
|
||||||
|
|
||||||
if key.GetExpiration() != nil {
|
}
|
||||||
expiration = ColourTime(key.GetExpiration().AsTime())
|
err = pterm.DefaultTable.WithHasHeader().WithData(tableData).Render()
|
||||||
}
|
if err != nil {
|
||||||
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Failed to render pterm table: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
tableData = append(tableData, []string{
|
return
|
||||||
strconv.FormatUint(key.GetId(), util.Base10),
|
}
|
||||||
key.GetPrefix(),
|
},
|
||||||
expiration,
|
|
||||||
key.GetCreatedAt().AsTime().Format(HeadscaleDateTimeFormat),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
return pterm.DefaultTable.WithHasHeader().WithData(tableData).Render()
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var createAPIKeyCmd = &cobra.Command{
|
var createAPIKeyCmd = &cobra.Command{
|
||||||
@@ -83,79 +111,91 @@ Creates a new Api key, the Api key is only visible on creation
|
|||||||
and cannot be retrieved again.
|
and cannot be retrieved again.
|
||||||
If you loose a key, create a new one and revoke (expire) the old one.`,
|
If you loose a key, create a new one and revoke (expire) the old one.`,
|
||||||
Aliases: []string{"c", "new"},
|
Aliases: []string{"c", "new"},
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
expiration, err := expirationFromFlag(cmd)
|
output, _ := cmd.Flags().GetString("output")
|
||||||
|
|
||||||
|
log.Trace().
|
||||||
|
Msg("Preparing to create ApiKey")
|
||||||
|
|
||||||
|
request := &v1.CreateApiKeyRequest{}
|
||||||
|
|
||||||
|
durationStr, _ := cmd.Flags().GetString("expiration")
|
||||||
|
|
||||||
|
duration, err := model.ParseDuration(durationStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Could not parse duration: %s\n", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.CreateApiKey(ctx, &v1.CreateApiKeyRequest{
|
expiration := time.Now().UTC().Add(time.Duration(duration))
|
||||||
Expiration: expiration,
|
|
||||||
})
|
log.Trace().
|
||||||
|
Dur("expiration", time.Duration(duration)).
|
||||||
|
Msg("expiration has been set")
|
||||||
|
|
||||||
|
request.Expiration = timestamppb.New(expiration)
|
||||||
|
|
||||||
|
ctx, client, conn, cancel := getHeadscaleCLIClient()
|
||||||
|
defer cancel()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
response, err := client.CreateApiKey(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating api key: %w", err)
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Cannot create Api Key: %s\n", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return printOutput(cmd, response.GetApiKey(), response.GetApiKey())
|
SuccessOutput(response.GetApiKey(), response.GetApiKey(), output)
|
||||||
}),
|
},
|
||||||
}
|
|
||||||
|
|
||||||
// apiKeyIDOrPrefix reads --id and --prefix from cmd and validates that
|
|
||||||
// exactly one is provided.
|
|
||||||
func apiKeyIDOrPrefix(cmd *cobra.Command) (uint64, string, error) {
|
|
||||||
id, _ := cmd.Flags().GetUint64("id")
|
|
||||||
prefix, _ := cmd.Flags().GetString("prefix")
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case id == 0 && prefix == "":
|
|
||||||
return 0, "", fmt.Errorf("either --id or --prefix must be provided: %w", errMissingParameter)
|
|
||||||
case id != 0 && prefix != "":
|
|
||||||
return 0, "", fmt.Errorf("only one of --id or --prefix can be provided: %w", errMissingParameter)
|
|
||||||
}
|
|
||||||
|
|
||||||
return id, prefix, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var expireAPIKeyCmd = &cobra.Command{
|
var expireAPIKeyCmd = &cobra.Command{
|
||||||
Use: "expire",
|
Use: "expire",
|
||||||
Short: "Expire an ApiKey",
|
Short: "Expire an ApiKey",
|
||||||
Aliases: []string{"revoke", "exp", "e"},
|
Aliases: []string{"revoke", "exp", "e"},
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
id, prefix, err := apiKeyIDOrPrefix(cmd)
|
output, _ := cmd.Flags().GetString("output")
|
||||||
|
|
||||||
|
prefix, err := cmd.Flags().GetString("prefix")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Error getting prefix from CLI flag: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
response, err := client.ExpireApiKey(ctx, &v1.ExpireApiKeyRequest{
|
ctx, client, conn, cancel := getHeadscaleCLIClient()
|
||||||
Id: id,
|
defer cancel()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
request := &v1.ExpireApiKeyRequest{
|
||||||
Prefix: prefix,
|
Prefix: prefix,
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("expiring api key: %w", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return printOutput(cmd, response, "Key expired")
|
response, err := client.ExpireApiKey(ctx, request)
|
||||||
}),
|
if err != nil {
|
||||||
}
|
ErrorOutput(
|
||||||
|
err,
|
||||||
var deleteAPIKeyCmd = &cobra.Command{
|
fmt.Sprintf("Cannot expire Api Key: %s\n", err),
|
||||||
Use: "delete",
|
output,
|
||||||
Short: "Delete an ApiKey",
|
)
|
||||||
Aliases: []string{"remove", "del"},
|
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
return
|
||||||
id, prefix, err := apiKeyIDOrPrefix(cmd)
|
}
|
||||||
if err != nil {
|
|
||||||
return err
|
SuccessOutput(response, "Key expired", output)
|
||||||
}
|
},
|
||||||
|
|
||||||
response, err := client.DeleteApiKey(ctx, &v1.DeleteApiKeyRequest{
|
|
||||||
Id: id,
|
|
||||||
Prefix: prefix,
|
|
||||||
})
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("deleting api key: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return printOutput(cmd, response, "Key deleted")
|
|
||||||
}),
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,93 +0,0 @@
|
|||||||
package cli
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
|
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
rootCmd.AddCommand(authCmd)
|
|
||||||
|
|
||||||
authRegisterCmd.Flags().StringP("user", "u", "", "User")
|
|
||||||
authRegisterCmd.Flags().String("auth-id", "", "Auth ID")
|
|
||||||
mustMarkRequired(authRegisterCmd, "user", "auth-id")
|
|
||||||
authCmd.AddCommand(authRegisterCmd)
|
|
||||||
|
|
||||||
authApproveCmd.Flags().String("auth-id", "", "Auth ID")
|
|
||||||
mustMarkRequired(authApproveCmd, "auth-id")
|
|
||||||
authCmd.AddCommand(authApproveCmd)
|
|
||||||
|
|
||||||
authRejectCmd.Flags().String("auth-id", "", "Auth ID")
|
|
||||||
mustMarkRequired(authRejectCmd, "auth-id")
|
|
||||||
authCmd.AddCommand(authRejectCmd)
|
|
||||||
}
|
|
||||||
|
|
||||||
var authCmd = &cobra.Command{
|
|
||||||
Use: "auth",
|
|
||||||
Short: "Manage node authentication and approval",
|
|
||||||
}
|
|
||||||
|
|
||||||
var authRegisterCmd = &cobra.Command{
|
|
||||||
Use: "register",
|
|
||||||
Short: "Register a node to your network",
|
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
|
||||||
user, _ := cmd.Flags().GetString("user")
|
|
||||||
authID, _ := cmd.Flags().GetString("auth-id")
|
|
||||||
|
|
||||||
request := &v1.AuthRegisterRequest{
|
|
||||||
AuthId: authID,
|
|
||||||
User: user,
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := client.AuthRegister(ctx, request)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("registering node: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return printOutput(
|
|
||||||
cmd,
|
|
||||||
response.GetNode(),
|
|
||||||
fmt.Sprintf("Node %s registered", response.GetNode().GetGivenName()))
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
var authApproveCmd = &cobra.Command{
|
|
||||||
Use: "approve",
|
|
||||||
Short: "Approve a pending authentication request",
|
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
|
||||||
authID, _ := cmd.Flags().GetString("auth-id")
|
|
||||||
|
|
||||||
request := &v1.AuthApproveRequest{
|
|
||||||
AuthId: authID,
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := client.AuthApprove(ctx, request)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("approving auth request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return printOutput(cmd, response, "Auth request approved")
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
|
|
||||||
var authRejectCmd = &cobra.Command{
|
|
||||||
Use: "reject",
|
|
||||||
Short: "Reject a pending authentication request",
|
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
|
||||||
authID, _ := cmd.Flags().GetString("auth-id")
|
|
||||||
|
|
||||||
request := &v1.AuthRejectRequest{
|
|
||||||
AuthId: authID,
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := client.AuthReject(ctx, request)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("rejecting auth request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return printOutput(cmd, response, "Auth request rejected")
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,7 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/rs/zerolog/log"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -14,12 +13,10 @@ var configTestCmd = &cobra.Command{
|
|||||||
Use: "configtest",
|
Use: "configtest",
|
||||||
Short: "Test the configuration.",
|
Short: "Test the configuration.",
|
||||||
Long: "Run a test of the configuration and exit.",
|
Long: "Run a test of the configuration and exit.",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
_, err := newHeadscaleServerWithConfig()
|
_, err := getHeadscaleApp()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("configuration error: %w", err)
|
log.Fatal().Caller().Err(err).Msg("Error initializing")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,22 +1,48 @@
|
|||||||
package cli
|
package cli
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
v1 "github.com/juanfont/headscale/gen/go/headscale/v1"
|
||||||
"github.com/juanfont/headscale/hscontrol/types"
|
"github.com/rs/zerolog/log"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
"tailscale.com/types/key"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
errPreAuthKeyMalformed = Error("key is malformed. expected 64 hex characters with `nodekey` prefix")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Error is used to compare errors as per https://dave.cheney.net/2016/04/07/constant-errors
|
||||||
|
type Error string
|
||||||
|
|
||||||
|
func (e Error) Error() string { return string(e) }
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(debugCmd)
|
rootCmd.AddCommand(debugCmd)
|
||||||
|
|
||||||
createNodeCmd.Flags().StringP("name", "", "", "Name")
|
createNodeCmd.Flags().StringP("name", "", "", "Name")
|
||||||
|
err := createNodeCmd.MarkFlagRequired("name")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("")
|
||||||
|
}
|
||||||
createNodeCmd.Flags().StringP("user", "u", "", "User")
|
createNodeCmd.Flags().StringP("user", "u", "", "User")
|
||||||
createNodeCmd.Flags().StringP("key", "k", "", "Key")
|
|
||||||
mustMarkRequired(createNodeCmd, "name", "user", "key")
|
|
||||||
|
|
||||||
|
createNodeCmd.Flags().StringP("namespace", "n", "", "User")
|
||||||
|
createNodeNamespaceFlag := createNodeCmd.Flags().Lookup("namespace")
|
||||||
|
createNodeNamespaceFlag.Deprecated = deprecateNamespaceMessage
|
||||||
|
createNodeNamespaceFlag.Hidden = true
|
||||||
|
|
||||||
|
err = createNodeCmd.MarkFlagRequired("user")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("")
|
||||||
|
}
|
||||||
|
createNodeCmd.Flags().StringP("key", "k", "", "Key")
|
||||||
|
err = createNodeCmd.MarkFlagRequired("key")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal().Err(err).Msg("")
|
||||||
|
}
|
||||||
createNodeCmd.Flags().
|
createNodeCmd.Flags().
|
||||||
StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to advertise")
|
StringSliceP("route", "r", []string{}, "List (or repeated flags) of routes to advertise")
|
||||||
|
|
||||||
@@ -32,20 +58,67 @@ var debugCmd = &cobra.Command{
|
|||||||
var createNodeCmd = &cobra.Command{
|
var createNodeCmd = &cobra.Command{
|
||||||
Use: "create-node",
|
Use: "create-node",
|
||||||
Short: "Create a node that can be registered with `nodes register <>` command",
|
Short: "Create a node that can be registered with `nodes register <>` command",
|
||||||
RunE: grpcRunE(func(ctx context.Context, client v1.HeadscaleServiceClient, cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
user, _ := cmd.Flags().GetString("user")
|
output, _ := cmd.Flags().GetString("output")
|
||||||
name, _ := cmd.Flags().GetString("name")
|
|
||||||
registrationID, _ := cmd.Flags().GetString("key")
|
|
||||||
|
|
||||||
_, err := types.AuthIDFromString(registrationID)
|
user, err := cmd.Flags().GetString("user")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("parsing machine key: %w", err)
|
ErrorOutput(err, fmt.Sprintf("Error getting user: %s", err), output)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
routes, _ := cmd.Flags().GetStringSlice("route")
|
ctx, client, conn, cancel := getHeadscaleCLIClient()
|
||||||
|
defer cancel()
|
||||||
|
defer conn.Close()
|
||||||
|
|
||||||
|
name, err := cmd.Flags().GetString("name")
|
||||||
|
if err != nil {
|
||||||
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Error getting node from flag: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
machineKey, err := cmd.Flags().GetString("key")
|
||||||
|
if err != nil {
|
||||||
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Error getting key from flag: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var mkey key.MachinePublic
|
||||||
|
err = mkey.UnmarshalText([]byte(machineKey))
|
||||||
|
if err != nil {
|
||||||
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Failed to parse machine key from flag: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
routes, err := cmd.Flags().GetStringSlice("route")
|
||||||
|
if err != nil {
|
||||||
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Error getting routes from flag: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
request := &v1.DebugCreateNodeRequest{
|
request := &v1.DebugCreateNodeRequest{
|
||||||
Key: registrationID,
|
Key: machineKey,
|
||||||
Name: name,
|
Name: name,
|
||||||
User: user,
|
User: user,
|
||||||
Routes: routes,
|
Routes: routes,
|
||||||
@@ -53,9 +126,15 @@ var createNodeCmd = &cobra.Command{
|
|||||||
|
|
||||||
response, err := client.DebugCreateNode(ctx, request)
|
response, err := client.DebugCreateNode(ctx, request)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("creating node: %w", err)
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Cannot create node: %s", status.Convert(err).Message()),
|
||||||
|
output,
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
return printOutput(cmd, response.GetNode(), "Node created")
|
SuccessOutput(response.GetNode(), "Node created", output)
|
||||||
}),
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ var dumpConfigCmd = &cobra.Command{
|
|||||||
Use: "dumpConfig",
|
Use: "dumpConfig",
|
||||||
Short: "dump current config to /etc/headscale/config.dump.yaml, integration test only",
|
Short: "dump current config to /etc/headscale/config.dump.yaml, integration test only",
|
||||||
Hidden: true,
|
Hidden: true,
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Args: func(cmd *cobra.Command, args []string) error {
|
||||||
err := viper.WriteConfigAs("/etc/headscale/config.dump.yaml")
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("dumping config: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
err := viper.WriteConfigAs("/etc/headscale/config.dump.yaml")
|
||||||
|
if err != nil {
|
||||||
|
//nolint
|
||||||
|
fmt.Println("Failed to dump config")
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,17 +21,22 @@ var generateCmd = &cobra.Command{
|
|||||||
var generatePrivateKeyCmd = &cobra.Command{
|
var generatePrivateKeyCmd = &cobra.Command{
|
||||||
Use: "private-key",
|
Use: "private-key",
|
||||||
Short: "Generate a private key for the headscale server",
|
Short: "Generate a private key for the headscale server",
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
Run: func(cmd *cobra.Command, args []string) {
|
||||||
|
output, _ := cmd.Flags().GetString("output")
|
||||||
machineKey := key.NewMachine()
|
machineKey := key.NewMachine()
|
||||||
|
|
||||||
machineKeyStr, err := machineKey.MarshalText()
|
machineKeyStr, err := machineKey.MarshalText()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("marshalling machine key: %w", err)
|
ErrorOutput(
|
||||||
|
err,
|
||||||
|
fmt.Sprintf("Error getting machine key from flag: %s", err),
|
||||||
|
output,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return printOutput(cmd, map[string]string{
|
SuccessOutput(map[string]string{
|
||||||
"private_key": string(machineKeyStr),
|
"private_key": string(machineKeyStr),
|
||||||
},
|
},
|
||||||
string(machineKeyStr))
|
string(machineKeyStr), output)
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user