Merge branch 'main' into release/v0.2
This commit is contained in:
commit
a60788c50c
3
.github/actions/auto-tag/action.yml
vendored
3
.github/actions/auto-tag/action.yml
vendored
@ -26,6 +26,9 @@ runs:
|
||||
# main → latest
|
||||
type=raw,enable=${{ github.ref == 'refs/heads/main' }},value=latest
|
||||
|
||||
# commit → short sha
|
||||
type=sha,format=short,prefix=
|
||||
|
||||
# release tag(v1.2.3)
|
||||
type=ref,event=tag
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
13
.github/workflows/build-base-images.yml
vendored
13
.github/workflows/build-base-images.yml
vendored
@ -145,10 +145,17 @@ jobs:
|
||||
# -------------------------------------------------------------
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Resolve short sha tag
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "sha_short=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}:${{ steps.vars.outputs.sha_short }}
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
@ -161,7 +168,7 @@ jobs:
|
||||
# -------------------------------------------------------------
|
||||
- uses: aquasecurity/trivy-action@0.28.0
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}:${{ steps.vars.outputs.sha_short }}
|
||||
severity: HIGH,CRITICAL
|
||||
exit-code: '1'
|
||||
|
||||
@ -173,5 +180,5 @@ jobs:
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: |
|
||||
COSIGN_IMAGE=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}@${{ steps.build.outputs.digest }}
|
||||
COSIGN_IMAGE=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.image.name }}:${{ steps.vars.outputs.sha_short }}
|
||||
cosign sign --yes "$COSIGN_IMAGE"
|
||||
|
||||
39
.github/workflows/build-service-images.yml
vendored
39
.github/workflows/build-service-images.yml
vendored
@ -83,10 +83,10 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
service:
|
||||
- { name: account, workdir: account, dockerfile: account/Dockerfile }
|
||||
- { name: dashboard, workdir: dashboard, dockerfile: dashboard/Dockerfile }
|
||||
- { name: rag-server, workdir: rag-server, dockerfile: rag-server/Dockerfile }
|
||||
- { name: xcontrol-init, workdir: ., dockerfile: xcontrol-init/Dockerfile }
|
||||
- { name: account, image: accounts, workdir: account, dockerfile: account/Dockerfile }
|
||||
- { name: dashboard, image: dashboard, workdir: dashboard, dockerfile: dashboard/Dockerfile }
|
||||
- { name: rag-server, image: rag-server, workdir: rag-server, dockerfile: rag-server/Dockerfile }
|
||||
- { name: xcontrol-init, image: xcontrol-init, workdir: ., dockerfile: xcontrol-init/Dockerfile }
|
||||
|
||||
steps:
|
||||
# -------------------------------------------------------------
|
||||
@ -110,7 +110,7 @@ jobs:
|
||||
id: meta
|
||||
uses: ./.github/actions/auto-tag
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.image }}
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# Docker Buildx setup
|
||||
@ -157,9 +157,9 @@ jobs:
|
||||
run: |
|
||||
set -euo pipefail
|
||||
|
||||
SERVICE="${{ matrix.service.name }}"
|
||||
ORIGIN_IMG="${{ env.REGISTRY }}/${{ env.ORG }}/${SERVICE}@${{ steps.build.outputs.digest }}"
|
||||
TARGET_REPO="docker.io/${TARGET_NS}/${SERVICE}"
|
||||
IMAGE_NAME="${{ matrix.service.image }}"
|
||||
ORIGIN_IMG="${{ env.REGISTRY }}/${{ env.ORG }}/${IMAGE_NAME}@${{ steps.build.outputs.digest }}"
|
||||
TARGET_REPO="docker.io/${TARGET_NS}/${IMAGE_NAME}"
|
||||
|
||||
TAG="latest"
|
||||
docker pull "$ORIGIN_IMG"
|
||||
@ -173,10 +173,10 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
service:
|
||||
- { name: dashboard, workdir: dashboard, dockerfile: dashboard/Dockerfile }
|
||||
- { name: account, workdir: account, dockerfile: account/Dockerfile }
|
||||
- { name: rag-server, workdir: rag-server, dockerfile: rag-server/Dockerfile }
|
||||
- { name: xcontrol-init, workdir: ., dockerfile: xcontrol-init/Dockerfile }
|
||||
- { name: dashboard, image: dashboard, workdir: dashboard, dockerfile: dashboard/Dockerfile }
|
||||
- { name: account, image: accounts, workdir: account, dockerfile: account/Dockerfile }
|
||||
- { name: rag-server, image: rag-server, workdir: rag-server, dockerfile: rag-server/Dockerfile }
|
||||
- { name: xcontrol-init, image: xcontrol-init, workdir: ., dockerfile: xcontrol-init/Dockerfile }
|
||||
|
||||
steps:
|
||||
# -------------------------------------------------------------
|
||||
@ -184,17 +184,24 @@ jobs:
|
||||
# -------------------------------------------------------------
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Resolve short sha tag
|
||||
id: vars
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
echo "sha_short=${GITHUB_SHA::7}" >> "$GITHUB_OUTPUT"
|
||||
|
||||
# -------------------------------------------------------------
|
||||
# SBOM Generation
|
||||
# -------------------------------------------------------------
|
||||
- uses: anchore/sbom-action@v0
|
||||
with:
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
|
||||
image: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.image }}:${{ steps.vars.outputs.sha_short }}
|
||||
output-file: sbom.spdx.json
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: sbom-${{ matrix.service.name }}
|
||||
name: sbom-${{ matrix.service.image }}
|
||||
path: sbom.spdx.json
|
||||
|
||||
# -------------------------------------------------------------
|
||||
@ -202,7 +209,7 @@ jobs:
|
||||
# -------------------------------------------------------------
|
||||
- uses: aquasecurity/trivy-action@0.28.0
|
||||
with:
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
|
||||
image-ref: ${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.image }}:${{ steps.vars.outputs.sha_short }}
|
||||
severity: HIGH,CRITICAL
|
||||
exit-code: '1'
|
||||
|
||||
@ -217,5 +224,5 @@ jobs:
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: "true"
|
||||
run: |
|
||||
IMG=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.name }}@${{ steps.build.outputs.digest }}
|
||||
IMG=${{ env.REGISTRY }}/${{ env.ORG }}/${{ matrix.service.image }}:${{ steps.vars.outputs.sha_short }}
|
||||
cosign sign --yes "$IMG"
|
||||
|
||||
4
.github/workflows/check-xcontrol-image.yaml
vendored
4
.github/workflows/check-xcontrol-image.yaml
vendored
@ -30,13 +30,13 @@ jobs:
|
||||
IMAGES=(
|
||||
"ghcr.io/cloud-neutral-toolkit/openresty-geoip"
|
||||
"ghcr.io/cloud-neutral-toolkit/postgres-runtime"
|
||||
"ghcr.io/cloud-neutral-toolkit/account"
|
||||
"ghcr.io/cloud-neutral-toolkit/accounts"
|
||||
"ghcr.io/cloud-neutral-toolkit/dashboard"
|
||||
"ghcr.io/cloud-neutral-toolkit/rag-server"
|
||||
"ghcr.io/cloud-neutral-toolkit/xcontrol-init"
|
||||
"docker.io/cloudneutral/openresty-geoip"
|
||||
"docker.io/cloudneutral/postgres-runtime"
|
||||
"docker.io/cloudneutral/account"
|
||||
"docker.io/cloudneutral/accounts"
|
||||
"docker.io/cloudneutral/dashboard"
|
||||
"docker.io/cloudneutral/rag-server"
|
||||
"docker.io/cloudneutral/xcontrol-init"
|
||||
|
||||
@ -112,6 +112,14 @@ type testEmailSender struct {
|
||||
messages []capturedEmail
|
||||
}
|
||||
|
||||
type stubAgentStatusReader struct {
|
||||
statuses []agentserver.StatusSnapshot
|
||||
}
|
||||
|
||||
func (s stubAgentStatusReader) Statuses() []agentserver.StatusSnapshot {
|
||||
return append([]agentserver.StatusSnapshot(nil), s.statuses...)
|
||||
}
|
||||
|
||||
func (s *testEmailSender) Send(ctx context.Context, msg EmailMessage) error {
|
||||
_ = ctx
|
||||
s.mu.Lock()
|
||||
@ -643,6 +651,60 @@ func TestSyncConfigSnapshotFallsBackWhenRenderFails(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSyncConfigSnapshotIncludesNodeDisplayMetadata(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
router, _, token := newAuthenticatedSyncHarness(t, WithAgentStatusReader(stubAgentStatusReader{
|
||||
statuses: []agentserver.StatusSnapshot{
|
||||
{Agent: agentserver.Identity{ID: "jp-xhttp.svc.plus", Name: "Japan Node"}},
|
||||
{Agent: agentserver.Identity{ID: "us-xhttp.svc.plus", Name: "US Node"}},
|
||||
},
|
||||
}))
|
||||
|
||||
req := httptest.NewRequest(http.MethodGet, "/api/auth/sync/config?since_version=0", nil)
|
||||
req.Header.Set("Authorization", "Bearer "+token)
|
||||
rr := httptest.NewRecorder()
|
||||
router.ServeHTTP(rr, req)
|
||||
|
||||
if rr.Code != http.StatusOK {
|
||||
t.Fatalf("expected sync config success, got %d: %s", rr.Code, rr.Body.String())
|
||||
}
|
||||
|
||||
resp := decodeSyncConfigResponse(t, rr)
|
||||
if len(resp.Nodes) != 2 {
|
||||
t.Fatalf("expected 2 nodes, got %d", len(resp.Nodes))
|
||||
}
|
||||
|
||||
byHost := make(map[string]map[string]interface{}, len(resp.Nodes))
|
||||
for _, node := range resp.Nodes {
|
||||
host, _ := node["host"].(string)
|
||||
if strings.TrimSpace(host) == "" {
|
||||
t.Fatalf("expected node host to be populated: %#v", node)
|
||||
}
|
||||
byHost[host] = node
|
||||
}
|
||||
|
||||
jp := byHost["jp-xhttp.svc.plus"]
|
||||
if jp == nil {
|
||||
t.Fatalf("expected jp-xhttp.svc.plus node in response: %#v", byHost)
|
||||
}
|
||||
if got, _ := jp["id"].(string); got != "jp-xhttp.svc.plus" {
|
||||
t.Fatalf("expected node id to match host, got %q", got)
|
||||
}
|
||||
if got, _ := jp["name"].(string); got != "Japan Node" {
|
||||
t.Fatalf("expected node name to preserve display name, got %q", got)
|
||||
}
|
||||
if got, _ := jp["display_name"].(string); got != "Japan Node" {
|
||||
t.Fatalf("expected display_name to preserve display name, got %q", got)
|
||||
}
|
||||
if got, _ := jp["server_name"].(string); got != "jp-xhttp.svc.plus" {
|
||||
t.Fatalf("expected server_name to match host, got %q", got)
|
||||
}
|
||||
if got, _ := jp["uri_scheme_xhttp"].(string); strings.TrimSpace(got) == "" {
|
||||
t.Fatalf("expected uri_scheme_xhttp to be populated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestResendVerificationEndpoint(t *testing.T) {
|
||||
gin.SetMode(gin.TestMode)
|
||||
|
||||
|
||||
@ -92,6 +92,7 @@ func (h *handler) respondSyncConfigSnapshot(c *gin.Context) {
|
||||
for _, host := range hosts {
|
||||
nodeName := resolveNodeName(host, registeredNames)
|
||||
countryCode := countryCodeForHost(host)
|
||||
nodeID := host
|
||||
vlessURI := renderVLESSURIScheme(xhttpScheme, map[string]string{
|
||||
"UUID": proxyUUID,
|
||||
"DOMAIN": host,
|
||||
@ -104,8 +105,10 @@ func (h *handler) respondSyncConfigSnapshot(c *gin.Context) {
|
||||
})
|
||||
|
||||
profiles = append(profiles, gin.H{
|
||||
"id": strings.TrimSpace(user.ID),
|
||||
"id": nodeID,
|
||||
"remark": nodeName,
|
||||
"display_name": nodeName,
|
||||
"host": host,
|
||||
"address": host,
|
||||
"port": 443,
|
||||
"uuid": proxyUUID,
|
||||
@ -117,19 +120,24 @@ func (h *handler) respondSyncConfigSnapshot(c *gin.Context) {
|
||||
"vless_uri": vlessURI,
|
||||
})
|
||||
nodes = append(nodes, gin.H{
|
||||
"id": strings.TrimSpace(user.ID),
|
||||
"name": nodeName,
|
||||
"protocol": "vless",
|
||||
"transport": "xhttp",
|
||||
"security": "tls",
|
||||
"address": host,
|
||||
"port": 443,
|
||||
"uuid": proxyUUID,
|
||||
"flow": "",
|
||||
"source": "server",
|
||||
"country_code": countryCode,
|
||||
"updated_at": updatedAt,
|
||||
"vless_uri": vlessURI,
|
||||
"id": nodeID,
|
||||
"name": nodeName,
|
||||
"display_name": nodeName,
|
||||
"remark": nodeName,
|
||||
"host": host,
|
||||
"protocol": "vless",
|
||||
"transport": "xhttp",
|
||||
"security": "tls",
|
||||
"address": host,
|
||||
"port": 443,
|
||||
"server_name": host,
|
||||
"uuid": proxyUUID,
|
||||
"flow": "",
|
||||
"source": "server",
|
||||
"country_code": countryCode,
|
||||
"updated_at": updatedAt,
|
||||
"vless_uri": vlessURI,
|
||||
"uri_scheme_xhttp": vlessURI,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user