transtation.git

transtation

~ Your own VLESS + REALITY proxy with optional Cloudflare WARP egress. Server in a container or native; native client with a fail-closed killswitch.
git clone https://github.com/debuman/transtation.git

.github/workflows/ci.yml (4210B)

      1 name: ci
      2 
      3 on:
      4   push:
      5     branches: [main]
      6     tags: ["v*"]
      7   pull_request:
      8   workflow_dispatch:
      9 
     10 permissions:
     11   contents: read
     12 
     13 jobs:
     14   test:
     15     runs-on: ubuntu-latest
     16     steps:
     17       - uses: actions/checkout@v4
     18 
     19       - name: shellcheck
     20         run: sudo apt-get update -qq && sudo apt-get install -y -qq shellcheck
     21 
     22       - name: version strings must match the tag being released
     23         if: startsWith(github.ref, 'refs/tags/v')
     24         run: |
     25           want="${GITHUB_REF_NAME}"
     26           got=$(sed -n 's/^VERSION=${TT_VERSION:-\(v[0-9.]*\)}.*/\1/p' install.sh)
     27           echo "tag=$want  install.sh=$got"
     28           [ "$want" = "$got" ] || { echo "::error::install.sh pins $got but the tag is $want"; exit 1; }
     29           bad=$(grep -oE 'v1\.[0-9]+\.[0-9]+' install.sh README.md | grep -v ":$want$" || true)
     30           [ -z "$bad" ] || { echo "::error::stale version strings:"; echo "$bad"; exit 1; }
     31 
     32       # Builds both images for amd64 only and runs their offline self-checks.
     33       # Everything runs with --network none, so CI never registers a WARP
     34       # identity: hammering Cloudflare's registration endpoint from shared
     35       # runner IPs is how an entire address range gets rate-limited.
     36       - name: test
     37         run: sh test.sh
     38 
     39   publish:
     40     needs: test
     41     if: startsWith(github.ref, 'refs/tags/v')
     42     runs-on: ubuntu-latest
     43     permissions:
     44       contents: write
     45       packages: write
     46     steps:
     47       - uses: actions/checkout@v4
     48       - uses: docker/setup-qemu-action@v3
     49       - uses: docker/setup-buildx-action@v3
     50       - uses: docker/login-action@v3
     51         with:
     52           registry: ghcr.io
     53           username: ${{ github.actor }}
     54           password: ${{ secrets.GITHUB_TOKEN }}
     55 
     56       - id: meta
     57         uses: docker/metadata-action@v5
     58         with:
     59           images: ghcr.io/${{ github.repository_owner }}/transtation
     60           tags: |
     61             type=semver,pattern={{version}}
     62             type=semver,pattern=v{{version}}
     63             type=raw,value=latest,enable={{is_default_branch}}
     64             type=sha,format=long
     65 
     66       - id: build
     67         uses: docker/build-push-action@v6
     68         with:
     69           context: .
     70           file: server/Dockerfile
     71           platforms: linux/amd64,linux/arm64
     72           push: true
     73           tags: ${{ steps.meta.outputs.tags }}
     74           labels: ${{ steps.meta.outputs.labels }}
     75           # Provenance and SBOM attestations are off: they add a manifest list
     76           # entry that some older clients choke on, and the compose file is
     77           # already pinned by digest, which closes the mutable-tag hole for
     78           # free. Turn them on when a downstream consumer asks for them.
     79           provenance: false
     80           sbom: false
     81 
     82       # The digest goes into install.sh at release time so that the compose file
     83       # pins the image by content, not by a mutable tag.
     84       - name: digest
     85         run: echo "transtation -> ${{ steps.build.outputs.digest }}" >> "$GITHUB_STEP_SUMMARY"
     86 
     87       # The README tells people to check install.sh against a hash in the release
     88       # notes, so the release notes have to exist and have to carry that hash.
     89       - name: publish the release notes with the installer hash
     90         env:
     91           GH_TOKEN: ${{ github.token }}
     92         run: |
     93           sum=$(sha256sum install.sh | cut -d" " -f1)
     94           {
     95             echo "\`\`\`"
     96             echo "$sum  install.sh"
     97             echo "\`\`\`"
     98             echo
     99             echo "    curl -fsSLO https://raw.githubusercontent.com/${{ github.repository }}/${{ github.ref_name }}/install.sh"
    100             echo "    sha256sum install.sh    # must match the line above"
    101             echo "    less install.sh"
    102             echo "    sudo sh install.sh"
    103             echo
    104             echo "Image: \`ghcr.io/${{ github.repository_owner }}/transtation:${{ github.ref_name }}\` (amd64, arm64). The client is a native install, not a container."
    105             echo "The installer resolves the tag to a digest at install time and pins the compose file to it."
    106           } > notes.md
    107           gh release create "${{ github.ref_name }}" --title "${{ github.ref_name }}" --notes-file notes.md || \
    108             gh release edit "${{ github.ref_name }}" --notes-file notes.md