Skip to content

Commit f1b72f2

Browse files
committed
lint and fixup GHA
1 parent 48894cd commit f1b72f2

13 files changed

Lines changed: 186 additions & 180 deletions

File tree

.dockerignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,6 @@
22
.github
33
*.md
44
Dockerfile
5+
gha-creds-*.json
6+
renovate.json5
7+
*.yaml

.github/workflows/lint-test-build.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ jobs:
2222
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
2323

2424
- name: check valid yml
25-
run: yq . *.yml
25+
run: yq . *.yaml
2626

2727
- uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # v5
2828
with:
@@ -44,8 +44,9 @@ jobs:
4444

4545
build-push:
4646
needs: [lint-test]
47-
uses: libops/actions/.github/workflows/build-push.yaml@main
47+
uses: libops/actions/.github/workflows/build-push.yml@main
4848
permissions:
4949
contents: read
5050
packages: write
51+
id-token: write
5152
secrets: inherit

.goreleaser.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ before:
22
hooks:
33
- go mod tidy
44
builds:
5-
- binary: scyllaridae
5+
- binary: ppb
66
env:
77
- CGO_ENABLED=0
88
goos:

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM golang:1.24-alpine3.21@sha256:ba0e119509b381457e9bb434319f2ef7996ad7ca7ec11a66e4ecdd8da49b8ddf
1+
FROM golang:1.25-alpine3.22@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
22

33
WORKDIR /app
44

README.md

Lines changed: 42 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# proxy power button
1+
# proxy power button (ppb)
22

3-
A secure reverse proxy that automatically powers on Google Compute Engine instances when traffic arrives.
3+
A reverse proxy that automatically powers on Google Compute Engine instances when traffic arrives.
44

55
This service is designed to run on **Google Cloud Run as an ingress layer** in front of your full application stack running on Google Compute Engine. When traffic hits your Cloud Run endpoint, PPB automatically powers on the target GCE VM (if needed) and proxies the request through. This architecture allows you to run complete application stacks on cost-effective VMs while only paying for Cloud Run when traffic actually arrives.
66

@@ -19,7 +19,7 @@ Internet → Cloud Run (PPB) → Google Compute Engine (Full App Stack)
1919
PPB runs as a reverse proxy with intelligent rate limiting:
2020

2121
1. **Request handling**: Each authorized request attempts to power on the target machine if needed
22-
2. **Rate limiting**: Power-on attempts are rate limited with a configurable cooldown period (default 30s)
22+
2. **Rate limiting**: Power-on attempts are rate limited with a configurable cooldown period (default 30s)
2323
3. **API protection**: Prevents hammering Google Cloud APIs during high traffic periods
2424
4. **IP Security**: Only requests from allowed IP ranges can trigger machine power-on attempts
2525

@@ -42,61 +42,63 @@ type: google_compute_engine
4242
port: 80
4343
scheme: http
4444
allowedIps:
45-
- 127.0.0.1/32 # localhost
46-
- 10.0.0.0/8 # private networks
45+
- 127.0.0.1/32
46+
- 10.0.0.0/8
4747
- 172.16.0.0/12
4848
- 192.168.0.0/16
4949
ipForwardedHeader: X-Forwarded-For # header to check for real client IP
5050
ipDepth: 0 # depth in X-Forwarded-For chain
5151
powerOnCooldown: 30 # seconds between power-on attempts (default: 30)
52+
# metadata about the machine that will be turned on
53+
machineMetadata:
54+
project_id: foo
55+
zone: us-central1-a
56+
name: my-compute-instance-name
57+
usePrivateIp: false # true for VPC-native setups
5258
# Optional proxy timeout configuration (defaults shown)
5359
proxyTimeouts:
5460
dialTimeout: 120 # Connection dial timeout in seconds
55-
keepAlive: 120 # TCP keep-alive timeout in seconds
61+
keepAlive: 120 # TCP keep-alive timeout in seconds
5662
idleConnTimeout: 90 # Idle connection timeout in seconds
5763
tlsHandshakeTimeout: 10 # TLS handshake timeout in seconds
5864
expectContinueTimeout: 1 # Expect: 100-continue timeout in seconds
5965
maxIdleConns: 100 # Maximum idle connections
60-
machineMetadata:
61-
project_id: foo
62-
zone: us-central1-a
63-
name: my-compute-instance-name
64-
usePrivateIp: false # true for VPC-native setups
66+
6567
```
6668

6769
### Configuration Reference
6870

69-
| Field | Type | Required | Default | Description |
70-
|-------|------|----------|---------|-------------|
71-
| `type` | string | ✅ | - | Backend type, currently only `google_compute_engine` |
72-
| `port` | int | ✅ | - | Port on target machine to proxy to |
73-
| `scheme` | string | ✅ | - | Protocol scheme (`http` or `https`) |
74-
| `allowedIps` | []string | ✅ | - | CIDR ranges of IPs allowed to access the proxy |
75-
| `ipForwardedHeader` | string | ❌ | `""` | Header to check for real client IP (e.g., `X-Forwarded-For`) |
76-
| `ipDepth` | int | ❌ | `0` | Depth in forwarded header chain (0 = rightmost IP) |
77-
| `powerOnCooldown` | int | ❌ | `30` | Seconds between power-on attempts (rate limiting) |
78-
| `proxyTimeouts.dialTimeout` | int | ❌ | `120` | Connection dial timeout in seconds |
79-
| `proxyTimeouts.keepAlive` | int | ❌ | `120` | TCP keep-alive timeout in seconds |
80-
| `proxyTimeouts.idleConnTimeout` | int | ❌ | `90` | Idle connection timeout in seconds |
81-
| `proxyTimeouts.tlsHandshakeTimeout` | int | ❌ | `10` | TLS handshake timeout in seconds |
82-
| `proxyTimeouts.expectContinueTimeout` | int | ❌ | `1` | Expect: 100-continue timeout in seconds |
83-
| `proxyTimeouts.maxIdleConns` | int | ❌ | `100` | Maximum number of idle connections |
84-
| `machineMetadata.project_id` | string | ✅ | - | Google Cloud project ID |
85-
| `machineMetadata.zone` | string | ✅ | - | GCE zone (e.g., `us-central1-a`) |
86-
| `machineMetadata.name` | string | ✅ | - | GCE instance name |
87-
| `machineMetadata.usePrivateIp` | bool | ❌ | `false` | Use private IP for VPC-native setups |
88-
89-
Deploy this service on **Google Cloud Run** as the public endpoint for your application. Configure the `machineMetadata` to point to your GCE VM running the actual application stack. Only requests from allowed IPs will power on the VM and be proxied through.
71+
| Field | Type | Required | Default | Description |
72+
|-----------------------------------------|----------|----------|---------|--------------------------------------------------------------|
73+
| `type` | string | | - | Backend type, currently only `google_compute_engine` |
74+
| `port` | int | | - | Port on target machine to proxy to |
75+
| `scheme` | string | | - | Protocol scheme (`http` or `https`) |
76+
| `allowedIps` | []string | | - | CIDR ranges of IPs allowed to access the proxy |
77+
| `ipForwardedHeader` | string | | `""` | Header to check for real client IP (e.g., `X-Forwarded-For`) |
78+
| `ipDepth` | int | | `0` | Depth in forwarded header chain (0 = rightmost IP) |
79+
| `powerOnCooldown` | int | | `30` | Seconds between power-on attempts (rate limiting) |
80+
| `proxyTimeouts.dialTimeout` | int | | `120` | Connection dial timeout in seconds |
81+
| `proxyTimeouts.keepAlive` | int | | `120` | TCP keep-alive timeout in seconds |
82+
| `proxyTimeouts.idleConnTimeout` | int | | `90` | Idle connection timeout in seconds |
83+
| `proxyTimeouts.tlsHandshakeTimeout` | int | | `10` | TLS handshake timeout in seconds |
84+
| `proxyTimeouts.expectContinueTimeout` | int | | `1` | Expect: 100-continue timeout in seconds |
85+
| `proxyTimeouts.maxIdleConns` | int | | `100` | Maximum number of idle connections |
86+
| `machineMetadata.project_id` | string | | - | Google Cloud project ID |
87+
| `machineMetadata.zone` | string | | - | GCE zone (e.g., `us-central1-a`) |
88+
| `machineMetadata.name` | string | | - | GCE instance name |
89+
| `machineMetadata.usePrivateIp` | bool | | `false` | Use private IP for VPC-native setups |
90+
91+
Deploy this service on **Google Cloud Run** as the public endpoint for your application. Configure the `machineMetadata` to point to your GCE VM running the actual application stack. Only requests from allowed IPs will power on the VM and be proxied through. Set to `0.0.0.0/0` to allow any request to power on the machine.
9092

9193
### Environment Variables
9294

9395
PPB also supports these environment variables for runtime configuration:
9496

95-
| Variable | Description | Default |
96-
|----------|-------------|---------|
97-
| `PPB_CONFIG_PATH` | Path to YAML configuration file | Required |
98-
| `LOG_LEVEL` | Log level (`DEBUG`, `INFO`, `WARN`, `ERROR`) | `INFO` |
99-
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to service account JSON file | Uses default credentials |
97+
| Variable | Description | Default |
98+
|----------------------------------|----------------------------------------------|--------------------------|
99+
| `PPB_CONFIG_PATH` | Path to YAML configuration file | /app/ppb.yaml |
100+
| `LOG_LEVEL` | Log level (`DEBUG`, `INFO`, `WARN`, `ERROR`) | `INFO` |
101+
| `GOOGLE_APPLICATION_CREDENTIALS` | Path to service account JSON file | Uses default credentials |
100102

101103
## IAM Permissions
102104

@@ -150,7 +152,7 @@ gcloud projects add-iam-policy-binding PROJECT_ID \
150152
### Local development
151153

152154
```bash
153-
docker build -t ghcr.io/libops/ppb:development .
155+
docker build -t us-docker.pkg.dev/your/gar/ppb:development .
154156
docker run \
155157
-p 8080:8080 \
156158
-v $GOOGLE_APPLICATION_CREDENTIALS:/app/svc.json:ro \
@@ -159,7 +161,7 @@ docker run \
159161
--env GOOGLE_APPLICATION_CREDENTIALS=/app/svc.json \
160162
--env PRIVATE_IP=false \
161163
--env LOG_LEVEL=DEBUG \
162-
ghcr.io/libops/ppb:development
164+
us-docker.pkg.dev/your/gar/ppb:development
163165
```
164166

165167
PPB will act as a local ingress proxy to your GCE VM. Visit http://localhost:8080 and PPB will power on your target VM (if needed) then proxy your requests through to the application running on the VM.
@@ -170,7 +172,7 @@ Deploy PPB to Cloud Run and configure it as your application's public endpoint:
170172

171173
```bash
172174
gcloud run deploy ppb \
173-
--image=ghcr.io/libops/ppb:latest \
175+
--image=us-docker.pkg.dev/your/gar/ppb:latest \
174176
--set-env-vars="PPB_CONFIG_PATH=/app/ppb.yaml" \
175177
--service-account=your-ppb-service-account@project.iam.gserviceaccount.com \
176178
--allow-unauthenticated \

main.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ func main() {
5656
http.Error(w, "Forbidden", http.StatusForbidden)
5757
return
5858
}
59-
59+
6060
// Attempt to power on machine with cooldown protection
6161
ctx := context.Background()
6262
err := c.Machine.PowerOnWithCooldown(ctx, c.PowerOnCooldown)
@@ -65,7 +65,7 @@ func main() {
6565
http.Error(w, "Backend not available", http.StatusServiceUnavailable)
6666
return
6767
}
68-
68+
6969
p.SetHost()
7070
slog.Info(r.Method, "path", r.URL.Path, "host", r.Host)
7171
p.ServeHTTP(w, r)

pkg/config/config.go

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,25 +11,25 @@ import (
1111
)
1212

1313
type Config struct {
14-
Type string `yaml:"type"`
15-
Scheme string `yaml:"scheme"`
16-
Port int `yaml:"port"`
17-
AllowedIps []IPNet `yaml:"allowedIps"`
18-
IpForwardedHeader string `yaml:"ipForwardedHeader"`
19-
IpDepth int `yaml:"ipDepth"`
20-
PowerOnCooldown int `yaml:"powerOnCooldown"` // seconds
21-
ProxyTimeouts ProxyTimeouts `yaml:"proxyTimeouts"`
22-
MachineMetadata map[string]any `yaml:"machineMetadata"`
23-
Machine *machine.GoogleComputeEngine
14+
Type string `yaml:"type"`
15+
Scheme string `yaml:"scheme"`
16+
Port int `yaml:"port"`
17+
AllowedIps []IPNet `yaml:"allowedIps"`
18+
IpForwardedHeader string `yaml:"ipForwardedHeader"`
19+
IpDepth int `yaml:"ipDepth"`
20+
PowerOnCooldown int `yaml:"powerOnCooldown"` // seconds
21+
ProxyTimeouts ProxyTimeouts `yaml:"proxyTimeouts"`
22+
MachineMetadata map[string]any `yaml:"machineMetadata"`
23+
Machine *machine.GoogleComputeEngine
2424
}
2525

2626
type ProxyTimeouts struct {
27-
DialTimeout int `yaml:"dialTimeout"` // seconds, default: 120
28-
KeepAlive int `yaml:"keepAlive"` // seconds, default: 120
29-
IdleConnTimeout int `yaml:"idleConnTimeout"` // seconds, default: 90
30-
TLSHandshakeTimeout int `yaml:"tlsHandshakeTimeout"` // seconds, default: 10
27+
DialTimeout int `yaml:"dialTimeout"` // seconds, default: 120
28+
KeepAlive int `yaml:"keepAlive"` // seconds, default: 120
29+
IdleConnTimeout int `yaml:"idleConnTimeout"` // seconds, default: 90
30+
TLSHandshakeTimeout int `yaml:"tlsHandshakeTimeout"` // seconds, default: 10
3131
ExpectContinueTimeout int `yaml:"expectContinueTimeout"` // seconds, default: 1
32-
MaxIdleConns int `yaml:"maxIdleConns"` // default: 100
32+
MaxIdleConns int `yaml:"maxIdleConns"` // default: 100
3333
}
3434

3535
type IPNet struct {

0 commit comments

Comments
 (0)