Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 79 additions & 0 deletions .github/workflows/integration.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
name: Proxy Integration Tests

on:
workflow_dispatch:
inputs:
build:
type: boolean
description: Build from current tag before running tests

jobs:
determine-tag:
runs-on: ubuntu-latest
outputs:
version: ${{ steps.metadata.outputs.VERSION }}
commit_hash: ${{ steps.metadata.outputs.COMMIT_HASH }}
build_timestamp: ${{ steps.metadata.outputs.BUILD_TIMESTAMP }}
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Determine metadata
id: metadata
run: |
# Generate static metadata
echo "COMMIT_HASH=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
echo "BUILD_TIMESTAMP=$(date '+%Y-%m-%dT%H:%M:%S')" >> "$GITHUB_OUTPUT"

# Determine version
if [ "${{ inputs.build }}" == "true" ]; then
echo "VERSION=development" >> "$GITHUB_OUTPUT"
else
echo "VERSION=${{ github.ref_name }}" >> "$GITHUB_OUTPUT"
fi

integration:
runs-on: ubuntu-latest
needs: determine-tag
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Go
uses: actions/setup-go@v6
with:
go-version: "1.25.0"

- name: Initialize submodules
run: |
git submodule init
git submodule update

- name: Apply patches
run: |
git apply --directory paerser/ patches/nested_maps.diff

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
if: ${{ inputs.build == 'true' }}

- name: Build
uses: docker/build-push-action@v6
if: ${{ inputs.build == 'true' }}
with:
platforms: linux/amd64
tags: ghcr.io/${{ github.repository_owner }}/tinyauth:${{ needs.determine-tag.outputs.version }}
outputs: type=image,push=false
cache-from: type=gha
cache-to: type=gha,mode=max
build-args: |
VERSION=${{ needs.determine-tag.outputs.version }}
COMMIT_HASH=${{ needs.determine-tag.outputs.commit_hash }}
BUILD_TIMESTAMP=${{ needs.determine-tag.outputs.build_timestamp }}

- name: Set tinyauth version
run: |
sed -i "s/TINYAUTH_VERSION=.*/TINYAUTH_VERSION=${{ needs.determine-tag.outputs.version }}/" integration/.env

- name: Test
run: make integration
2 changes: 0 additions & 2 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: nightly

- name: Generate metadata
id: metadata
Expand Down
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -81,5 +81,11 @@ sql:
sqlc generate

# Go gen
.PHONY: generate
generate:
go run ./gen

# Proxy integration tests
.PHONY: integration
integration:
go run ./integration -- --log=false
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify how integration CLI parses arguments/flags (read-only reconnaissance).
# Expected: determine whether a leading standalone "--" would stop parsing --log=false.

rg -n -C3 --type go 'flag\.|pflag|cobra|urfave|os\.Args|log' integration

Repository: steveiliop56/tinyauth

Length of output: 6362


Remove the -- separator so the --log=false flag is properly parsed.

The -- separator in Go's flag package stops flag parsing, leaving --log=false as a positional argument instead of being processed as a flag. Remove it to allow the flag to be recognized.

Fix
 integration:
-	go run ./integration -- --log=false
+	go run ./integration --log=false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
go run ./integration -- --log=false
integration:
go run ./integration --log=false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Makefile` at line 91, The Makefile target currently runs "go run
./integration -- --log=false" which uses the "--" separator and prevents the
integration program from parsing the --log flag; remove the separator so the
command is "go run ./integration --log=false" (i.e., edit the Makefile line
containing go run ./integration to drop the standalone "--") so the flag is
parsed by the Go program.

16 changes: 16 additions & 0 deletions integration/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Nginx configuration
NGINX_VERSION=1.29

# Whoami configuration
WHOAMI_VERSION=latest

# Traefik configuration
TRAEFIK_VERSION=v3.6
TINYAUTH_HOST=tinyauth.127.0.0.1.sslip.io
WHOAMI_HOST=whoami.127.0.0.1.sslip.io

# Envoy configuration
ENVOY_VERSION=v1.33-latest

# Tinyauth configuration
TINYAUTH_VERSION=latest
15 changes: 15 additions & 0 deletions integration/config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
appUrl: http://tinyauth.127.0.0.1.sslip.io

auth:
users: test:$2a$10$eG88kFow83l5YRSlTSL2o.sZimjxFHrpiKdaSUZqpLBGX7Y2.4PZG

log:
json: true
level: trace

apps:
whoami:
config:
domain: whoami.127.0.0.1.sslip.io
path:
allow: /allow
16 changes: 16 additions & 0 deletions integration/docker-compose.envoy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
services:
envoy:
image: envoyproxy/envoy:${ENVOY_VERSION}
ports:
- 80:80
volumes:
- ./envoy.yml:/etc/envoy/envoy.yaml:ro

whoami:
image: traefik/whoami:${WHOAMI_VERSION}

tinyauth:
image: ghcr.io/steveiliop56/tinyauth:${TINYAUTH_VERSION}
command: --experimental.configfile=/data/config.yml
volumes:
- ./config.yml:/data/config.yml:ro
16 changes: 16 additions & 0 deletions integration/docker-compose.nginx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
services:
nginx:
image: nginx:${NGINX_VERSION}
ports:
- 80:80
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro

whoami:
image: traefik/whoami:${WHOAMI_VERSION}

tinyauth:
image: ghcr.io/steveiliop56/tinyauth:${TINYAUTH_VERSION}
command: --experimental.configfile=/data/config.yml
volumes:
- ./config.yml:/data/config.yml:ro
28 changes: 28 additions & 0 deletions integration/docker-compose.traefik.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
services:
traefik:
image: traefik:${TRAEFIK_VERSION}
command: |
--api.insecure=true
--providers.docker
--entryPoints.web.address=:80
ports:
- 80:80
volumes:
- /var/run/docker.sock:/var/run/docker.sock

whoami:
image: traefik/whoami:${WHOAMI_VERSION}
labels:
traefik.enable: true
traefik.http.routers.whoami.rule: Host(`${WHOAMI_HOST}`)
traefik.http.routers.whoami.middlewares: tinyauth

tinyauth:
image: ghcr.io/steveiliop56/tinyauth:${TINYAUTH_VERSION}
command: --experimental.configfile=/data/config.yml
volumes:
- ./config.yml:/data/config.yml:ro
labels:
traefik.enable: true
traefik.http.routers.tinyauth.rule: Host(`${TINYAUTH_HOST}`)
traefik.http.middlewares.tinyauth.forwardauth.address: http://tinyauth:3000/api/auth/traefik
105 changes: 105 additions & 0 deletions integration/envoy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
static_resources:
listeners:
- name: "listener_http"
address:
socket_address:
address: "0.0.0.0"
port_value: 80
filter_chains:
- filters:
- name: "envoy.filters.network.http_connection_manager"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager"
stat_prefix: "ingress_http"
use_remote_address: true
skip_xff_append: false
route_config:
name: "local_route"
virtual_hosts:
- name: "whoami_service"
domains: ["whoami.127.0.0.1.sslip.io"]
routes:
- match:
prefix: "/"
route:
cluster: "whoami"
- name: "tinyauth_service"
domains: ["tinyauth.127.0.0.1.sslip.io"]
typed_per_filter_config:
envoy.filters.http.ext_authz:
"@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthzPerRoute"
disabled: true
routes:
- match:
prefix: "/"
route:
cluster: "tinyauth"
http_filters:
- name: "envoy.filters.http.ext_authz"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.ext_authz.v3.ExtAuthz"
transport_api_version: "v3"
http_service:
path_prefix: "/api/auth/envoy?path="
server_uri:
uri: "tinyauth:3000"
cluster: "tinyauth"
timeout: "0.25s"
authorization_request:
allowed_headers:
patterns:
- exact: "authorization"
- exact: "accept"
- exact: "cookie"
headers_to_add:
- key: "x-forwarded-proto"
value: "%REQ(:SCHEME)%"
- key: "x-forwarded-host"
value: "%REQ(:AUTHORITY)%"
- key: "x-forwarded-uri"
value: "%REQ(:PATH)%"
authorization_response:
allowed_upstream_headers:
patterns:
- prefix: "remote-"
allowed_client_headers:
patterns:
- exact: "set-cookie"
- exact: "location"
allowed_client_headers_on_success:
patterns:
- exact: "set-cookie"
- exact: "location"
failure_mode_allow: false
- name: "envoy.filters.http.router"
typed_config:
"@type": "type.googleapis.com/envoy.extensions.filters.http.router.v3.Router"
clusters:
- name: "whoami"
connect_timeout: "0.25s"
type: "logical_dns"
dns_lookup_family: "v4_only"
lb_policy: "round_robin"
load_assignment:
cluster_name: "whoami"
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: "whoami"
port_value: 80
- name: "tinyauth"
connect_timeout: "0.25s"
type: "logical_dns"
dns_lookup_family: "v4_only"
lb_policy: "round_robin"
load_assignment:
cluster_name: "tinyauth"
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: "tinyauth"
port_value: 3000
62 changes: 62 additions & 0 deletions integration/integrarion_tests.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package main

import (
"fmt"
"io"
"net/http"
"strings"
)

func testUnauthorized(client *http.Client) error {
req, err := http.NewRequest("GET", WhoamiURL, nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return err
}
// nginx and envoy will throw us at the frontend
if resp.StatusCode != http.StatusUnauthorized && !strings.Contains(string(body), "<div id=\"root\"></div>") {
return fmt.Errorf("expected status code %d or to to contain '<div id=\"root\"></div>', got %d", http.StatusUnauthorized, resp.StatusCode)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix typo in assertion error message.

Line [26] has "or to to contain"; this makes failure output noisier than needed in CI logs.

Suggested fix
-		return fmt.Errorf("expected status code %d or to to contain '<div id=\"root\"></div>', got %d", http.StatusUnauthorized, resp.StatusCode)
+		return fmt.Errorf("expected status code %d or to contain '<div id=\"root\"></div>', got %d", http.StatusUnauthorized, resp.StatusCode)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
return fmt.Errorf("expected status code %d or to to contain '<div id=\"root\"></div>', got %d", http.StatusUnauthorized, resp.StatusCode)
return fmt.Errorf("expected status code %d or to contain '<div id=\"root\"></div>', got %d", http.StatusUnauthorized, resp.StatusCode)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@integration/integrarion_tests.go` at line 26, Fix the typo in the assertion
error message inside the fmt.Errorf call that currently reads "or to to contain"
— update the string to "or to contain" so the error message is clean; locate the
fmt.Errorf call in integrarion_tests.go (the line that constructs the error
about expected status code http.StatusUnauthorized and presence of '<div
id=\"root\"></div>') and correct the duplicated "to".

}
return nil
}

func testLoggedIn(client *http.Client) error {
req, err := http.NewRequest("GET", WhoamiURL, nil)
if err != nil {
return err
}
req.SetBasicAuth(DefaultUsername, DefaultPassword)
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode)
}
return nil
}

func testACLAllowed(client *http.Client) error {
req, err := http.NewRequest("GET", WhoamiURL+"/allow", nil)
if err != nil {
return err
}
resp, err := client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("expected status code %d, got %d", http.StatusOK, resp.StatusCode)
}
return nil
}
Loading
Loading