fix(tests): remove duplicate script stub appended to lab test files #13
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: CI | ||
| on: | ||
| push: | ||
| branches: [main, develop, 'feature/**', 'bugfix/**'] | ||
| pull_request: | ||
| branches: [main, develop] | ||
| permissions: | ||
| contents: read | ||
| security-events: write | ||
| jobs: | ||
| validate: | ||
| name: Validate Configuration | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Validate Docker Compose files | ||
| run: | | ||
| for f in docker/docker-compose.*.yml; do | ||
| echo "Validating: $f" | ||
| docker compose -f "$f" config --no-interpolate -q | ||
| done | ||
| - name: ShellCheck — lab test scripts | ||
| run: | | ||
| sudo apt-get install -y shellcheck -qq | ||
| shellcheck --severity=error tests/labs/*.sh | ||
| - name: Validate module manifest | ||
| run: | | ||
| python3 -c " | ||
| import sys, re | ||
| with open('it-stack-snipeit.yml') as f: | ||
| content = f.read() | ||
| required = ['module:', 'version:', 'phase:', 'category:', 'ports:'] | ||
| missing = [k for k in required if k not in content] | ||
| if missing: | ||
| print('Missing fields:', missing); sys.exit(1) | ||
| print('Manifest valid') | ||
| " | ||
| security-scan: | ||
| name: Security Scan | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Trivy — scan Dockerfile | ||
| uses: aquasecurity/trivy-action@0.28.0 | ||
| with: | ||
| scan-type: config | ||
| scan-ref: . | ||
| exit-code: '0' | ||
| severity: CRITICAL,HIGH | ||
| - name: Trivy — SARIF output | ||
| uses: aquasecurity/trivy-action@0.28.0 | ||
| with: | ||
| scan-type: config | ||
| scan-ref: . | ||
| format: sarif | ||
| output: trivy-results.sarif | ||
| - name: Upload SARIF to GitHub Security | ||
| uses: github/codeql-action/upload-sarif@v3 | ||
| if: always() | ||
| with: | ||
| sarif_file: trivy-results.sarif | ||
| lab-01-smoke: | ||
| name: Lab 01 — Smoke Test | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| continue-on-error: true # scaffold stubs; full lab runs on real VMs | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Generate CI env file | ||
| run: | | ||
| # Copy example env and inject CI-safe defaults for any unset port vars | ||
| if [ -f .env.example ]; then cp .env.example .env; fi | ||
| # Set port placeholder vars used in scaffold compose files | ||
| echo "firstPort=389" >> .env | ||
| echo "secondPort=9090" >> .env | ||
| - name: Validate standalone compose can start | ||
| run: | | ||
| docker compose -f docker/docker-compose.standalone.yml config --no-interpolate -q | ||
| echo "Standalone compose structure is valid" | ||
| - name: Start standalone stack | ||
| run: docker compose -f docker/docker-compose.standalone.yml up -d | ||
| - name: Wait for health | ||
| run: | | ||
| echo "Waiting for services..." | ||
| sleep 30 | ||
| docker compose -f docker/docker-compose.standalone.yml ps | ||
| - name: Run Lab 01 test script | ||
| run: bash tests/labs/test-lab-16-01.sh | ||
| - name: Collect logs on failure | ||
| if: failure() | ||
| run: docker compose -f docker/docker-compose.standalone.yml logs | ||
| - name: Cleanup | ||
| if: always() | ||
| run: docker compose -f docker/docker-compose.standalone.yml down -v | ||
| lab-02-smoke: | ||
| name: Lab 02 -- Snipe-IT External Dependencies (MariaDB + Mailhog) | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| continue-on-error: true | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Install tools | ||
| run: sudo apt-get install -y curl default-mysql-client -qq | ||
| - name: Validate LAN compose | ||
| run: docker compose -f docker/docker-compose.lan.yml config -q && echo "LAN compose valid" | ||
| - name: Start LAN stack | ||
| run: docker compose -f docker/docker-compose.lan.yml up -d | ||
| - name: Wait for MariaDB | ||
| run: timeout 120 bash -c 'until docker exec snipeit-l02-db mysqladmin ping -uroot -pRootLab02! --silent; do sleep 5; done' | ||
| - name: Wait for Mailhog | ||
| run: timeout 60 bash -c 'until curl -sf http://localhost:8711/api/v2/messages; do sleep 5; done' | ||
| - name: Wait for Snipe-IT web | ||
| run: timeout 300 bash -c 'until curl -o /dev/null -sw "%{http_code}" http://localhost:8411/ | grep -q "^[234]"; do sleep 10; done' | ||
| - name: Run Lab 16-02 test script | ||
| run: bash tests/labs/test-lab-16-02.sh --no-cleanup | ||
| - name: Collect logs on failure | ||
| if: failure() | ||
| run: docker compose -f docker/docker-compose.lan.yml logs | ||
| - name: Cleanup | ||
| if: always() | ||
| run: docker compose -f docker/docker-compose.lan.yml down -v | ||
| lab-03-smoke: | ||
| name: Lab 03 -- Snipe-IT Advanced Features (Redis sessions + dedicated queue worker) | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| continue-on-error: true | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Install tools | ||
| run: sudo apt-get install -y curl default-mysql-client redis-tools -qq | ||
| - name: Validate advanced compose | ||
| run: docker compose -f docker/docker-compose.advanced.yml config -q && echo "Advanced compose valid" | ||
| - name: Start advanced stack | ||
| run: docker compose -f docker/docker-compose.advanced.yml up -d | ||
| - name: Wait for MariaDB | ||
| run: timeout 120 bash -c 'until docker exec snipeit-a03-db mysqladmin ping -h localhost -uroot -pRootLab03! --silent; do sleep 5; done' | ||
| - name: Wait for Redis | ||
| run: timeout 60 bash -c 'until docker exec snipeit-a03-redis redis-cli ping | grep -q PONG; do sleep 5; done' | ||
| - name: Wait for Mailhog | ||
| run: timeout 60 bash -c 'until curl -sf http://localhost:8721/api/v2/messages; do sleep 5; done' | ||
| - name: Wait for Snipe-IT app | ||
| run: timeout 300 bash -c 'until curl -o /dev/null -sw "%{http_code}" http://localhost:8421/ | grep -q "^[23]"; do sleep 15; done' | ||
| - name: Run Lab 16-03 test script | ||
| run: bash tests/labs/test-lab-16-03.sh --no-cleanup | ||
| - name: Collect logs on failure | ||
| if: failure() | ||
| run: docker compose -f docker/docker-compose.advanced.yml logs | ||
| - name: Cleanup | ||
| if: always() | ||
| run: docker compose -f docker/docker-compose.advanced.yml down -v | ||
| lab-04-smoke: | ||
| name: Lab 04 -- Snipe-IT SSO Integration (Keycloak SAML + OpenLDAP) | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| continue-on-error: true | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Install tools | ||
| run: sudo apt-get install -y curl default-mysql-client netcat-openbsd ldap-utils | ||
| - name: Validate SSO compose | ||
| run: docker compose -f docker/docker-compose.sso.yml config -q && echo "SSO compose valid" | ||
| - name: Start SSO stack | ||
| run: docker compose -f docker/docker-compose.sso.yml up -d | ||
| - name: Wait for MariaDB | ||
| run: timeout 120 bash -c 'until docker exec snipeit-s04-db mysqladmin ping -uroot -pRootLab04! --silent; do sleep 5; done' | ||
| - name: Wait for OpenLDAP | ||
| run: timeout 120 bash -c 'until docker exec snipeit-s04-ldap ldapsearch -x -H ldap://localhost -b dc=lab,dc=local -D cn=admin,dc=lab,dc=local -w LdapLab04! cn=admin >/dev/null 2>&1; do sleep 5; done' | ||
| - name: Wait for Keycloak | ||
| run: timeout 300 bash -c 'until curl -sf http://localhost:8531/realms/master; do sleep 10; done' | ||
| - name: Wait for Mailhog | ||
| run: timeout 60 bash -c 'until curl -sf http://localhost:8731/api/v2/messages; do sleep 5; done' | ||
| - name: Wait for Snipe-IT app | ||
| run: timeout 300 bash -c 'until curl -o /dev/null -sw "%{http_code}" http://localhost:8431/ | grep -q "^[23]"; do sleep 15; done' | ||
| - name: Run Lab 16-04 test script | ||
| run: bash tests/labs/test-lab-16-04.sh --no-cleanup | ||
| - name: Collect logs on failure | ||
| if: failure() | ||
| run: docker compose -f docker/docker-compose.sso.yml logs | ||
| - name: Cleanup | ||
| if: always() | ||
| run: docker compose -f docker/docker-compose.sso.yml down -v | ||
| lab-05-smoke: | ||
| name: Lab 16-05 -- Snipe-IT Advanced Integration (INT-08b Snipe-IT<->Keycloak SAML + LDAP) | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| continue-on-error: true | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Install tools | ||
| run: sudo apt-get install -y curl default-mysql-client netcat-openbsd ldap-utils python3 -qq | ||
| - name: Validate integration compose | ||
| run: docker compose -f docker/docker-compose.integration.yml config -q && echo "Integration compose valid" | ||
| - name: Start integration stack | ||
| run: docker compose -f docker/docker-compose.integration.yml up -d | ||
| - name: Wait for MariaDB | ||
| run: timeout 120 bash -c 'until docker exec snipeit-i05-db mysqladmin ping -uroot -pRootLab05! --silent 2>/dev/null; do sleep 5; done' | ||
| - name: Wait for OpenLDAP | ||
| run: timeout 120 bash -c 'until docker exec snipeit-i05-ldap ldapsearch -x -H ldap://localhost -b dc=lab,dc=local -D cn=admin,dc=lab,dc=local -w LdapLab05! cn=admin >/dev/null 2>&1; do sleep 5; done' | ||
| - name: Wait for LDAP seed to exit | ||
| run: timeout 60 bash -c 'until [ "$(docker inspect --format={{.State.Status}} snipeit-i05-ldap-seed 2>/dev/null)" = "exited" ]; do sleep 3; done' | ||
| - name: Wait for Keycloak health/ready | ||
| run: timeout 300 bash -c 'until curl -sf http://localhost:8541/health/ready | grep -q UP; do sleep 10; done' | ||
| - name: Wait for WireMock | ||
| run: timeout 90 bash -c 'until curl -sf http://localhost:8762/__admin/health; do sleep 5; done' | ||
| - name: Wait for Snipe-IT | ||
| run: timeout 300 bash -c 'until curl -sf http://localhost:8441/ | grep -qi snipe; do sleep 15; done' | ||
| - name: Run Lab 16-05 test script | ||
| run: bash tests/labs/test-lab-16-05.sh --no-cleanup | ||
| - name: Collect logs on failure | ||
| if: failure() | ||
| run: docker compose -f docker/docker-compose.integration.yml logs | ||
| - name: Cleanup | ||
| if: always() | ||
| run: docker compose -f docker/docker-compose.integration.yml down -v | ||
| lab-06-smoke: | ||
| name: Lab 16-06 -- Snipe-IT Production Deployment (restart policy, resource limits, queue worker) | ||
| runs-on: ubuntu-latest | ||
| needs: validate | ||
| continue-on-error: true | ||
| steps: | ||
| - uses: actions/checkout@v4 | ||
| - name: Install tools | ||
| run: sudo apt-get install -y curl default-mysql-client netcat-openbsd ldap-utils | ||
| - name: Validate production compose | ||
| run: docker compose -f docker/docker-compose.production.yml config -q && echo "Production compose valid" | ||
| - name: Start production stack | ||
| run: docker compose -f docker/docker-compose.production.yml up -d | ||
| - name: Wait for MariaDB | ||
| run: | | ||
| for i in $(seq 1 18); do | ||
| docker exec snipeit-p06-db mysqladmin ping -uroot -pRootProd06! --silent 2>/dev/null && echo "DB ready" && break | ||
| echo "Waiting for DB... ($i/18)"; sleep 5 | ||
| done | ||
| - name: Wait for Keycloak | ||
| run: | | ||
| for i in $(seq 1 24); do | ||
| curl -sf http://localhost:8561/realms/master | grep -q realm && echo "KC ready" && break | ||
| echo "Waiting for KC... ($i/24)"; sleep 5 | ||
| done | ||
| - name: Wait for Mailhog | ||
| run: | | ||
| for i in $(seq 1 12); do | ||
| curl -sf http://localhost:8751/api/v2/messages > /dev/null && echo "MH ready" && break | ||
| echo "Waiting for MH... ($i/12)"; sleep 5 | ||
| done | ||
| - name: Wait for Snipe-IT | ||
| run: | | ||
| for i in $(seq 1 36); do | ||
| curl -sf http://localhost:8461/ | grep -qi html && echo "Snipe-IT ready" && break | ||
| echo "Waiting for Snipe-IT... ($i/36)"; sleep 5 | ||
| done | ||
| - name: Run Lab 16-06 test script | ||
| run: bash tests/labs/test-lab-16-06.sh --no-cleanup | ||
| - name: Collect logs on failure | ||
| if: failure() | ||
| run: docker compose -f docker/docker-compose.production.yml logs | ||
| - name: Cleanup | ||
| if: always() | ||
| run: docker compose -f docker/docker-compose.production.yml down -v | ||