ruslanmv commited on
Commit
8c4c4be
·
1 Parent(s): f26d6cd

Fist commit

Browse files
.github/workflows/dockerhub.yml ADDED
@@ -0,0 +1,147 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: 📦 Publish Docker (Docker Hub)
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: "Release tag (e.g., v1.2.3 or 1.2.3)"
10
+ required: true
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: dockerhub-publish-a2a-validator
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ build-and-push:
21
+ name: Build & Push (Docker Hub)
22
+ runs-on: ubuntu-latest
23
+
24
+ steps:
25
+ - name: Checkout
26
+ uses: actions/checkout@v4
27
+
28
+ # Normalize version from release tag or manual input
29
+ - name: Derive release version
30
+ id: version
31
+ shell: bash
32
+ run: |
33
+ if [ "${{ github.event_name }}" = "release" ]; then
34
+ RAW="${GITHUB_REF#refs/tags/}"
35
+ else
36
+ RAW="${{ github.event.inputs.version }}"
37
+ fi
38
+ if [ -z "$RAW" ]; then
39
+ echo "Version not provided."; exit 1
40
+ fi
41
+ if [[ "$RAW" =~ ^v ]]; then
42
+ RELEASE_TAG="$RAW"
43
+ SEMVER="${RAW#v}"
44
+ else
45
+ RELEASE_TAG="v$RAW"
46
+ SEMVER="$RAW"
47
+ fi
48
+ echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV
49
+ echo "SEMVER=$SEMVER" >> $GITHUB_ENV
50
+ echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
51
+ echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
52
+ echo "Resolved RELEASE_TAG=${RELEASE_TAG}, SEMVER=${SEMVER}, SHORT_SHA=${SHORT_SHA}"
53
+
54
+ # docker.io requires lowercase namespace
55
+ - name: Compute image name (lowercase)
56
+ id: img
57
+ shell: bash
58
+ run: |
59
+ USER_RAW="${{ secrets.DOCKERHUB_USERNAME }}"
60
+ USER_LC="${USER_RAW,,}"
61
+ IMAGE="docker.io/${USER_LC}/a2a-validator"
62
+ echo "IMAGE=$IMAGE" >> $GITHUB_ENV
63
+ echo "Image: $IMAGE"
64
+
65
+ - name: Set up QEMU (multi-arch)
66
+ uses: docker/setup-qemu-action@v3
67
+
68
+ - name: Set up Docker Buildx
69
+ uses: docker/setup-buildx-action@v3
70
+
71
+ - name: Docker Hub login
72
+ uses: docker/login-action@v3
73
+ with:
74
+ registry: docker.io
75
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
76
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
77
+
78
+ - name: Docker metadata (tags & labels)
79
+ id: meta
80
+ uses: docker/metadata-action@v5
81
+ with:
82
+ images: ${{ env.IMAGE }}
83
+ flavor: |
84
+ latest=false
85
+ tags: |
86
+ # stable semver tags (always)
87
+ type=raw,value=v${{ env.SEMVER }}
88
+ type=semver,pattern={{version}},value=${{ env.SEMVER }}
89
+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER }}
90
+ type=semver,pattern={{major}},value=${{ env.SEMVER }}
91
+ # short sha tag (always)
92
+ type=raw,value=sha-${{ env.SHORT_SHA }}
93
+ # latest only on release
94
+ type=raw,value=latest,enable=${{ github.event_name == 'release' }}
95
+ labels: |
96
+ org.opencontainers.image.title=a2a-validator
97
+ org.opencontainers.image.description=A2A Validator — web inspector & debugger for A2A agents
98
+ org.opencontainers.image.url=https://github.com/${{ github.repository }}
99
+ org.opencontainers.image.source=https://github.com/${{ github.repository }}
100
+ org.opencontainers.image.version=${{ env.SEMVER }}
101
+ org.opencontainers.image.revision=${{ github.sha }}
102
+ org.opencontainers.image.created=${{ env.BUILD_DATE }}
103
+
104
+ # Build & push using your Dockerfile
105
+ - name: Build & push (Docker Hub)
106
+ id: build
107
+ uses: docker/build-push-action@v6
108
+ with:
109
+ context: .
110
+ file: ./Dockerfile
111
+ push: true
112
+ platforms: linux/amd64,linux/arm64
113
+ tags: ${{ steps.meta.outputs.tags }}
114
+ labels: ${{ steps.meta.outputs.labels }}
115
+ cache-from: type=gha
116
+ cache-to: type=gha,mode=max
117
+ build-args: |
118
+ BUILD_VERSION=${{ env.SEMVER }}
119
+ BUILD_COMMIT=${{ github.sha }}
120
+ BUILD_DATE=${{ env.BUILD_DATE }}
121
+
122
+ # Guard 1: The image must NOT contain a baked /app/.env
123
+ - name: Sanity guard — no baked .env
124
+ shell: bash
125
+ run: |
126
+ REF="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)"
127
+ docker run --rm --entrypoint /bin/bash "$REF" -lc 'test ! -f /app/.env'
128
+ echo "OK: no baked /app/.env"
129
+
130
+ # Guard 2: The image must NOT contain a SQLite db (e.g. *.sqlite)
131
+ - name: Sanity guard — no baked SQLite DB
132
+ shell: bash
133
+ run: |
134
+ REF="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)"
135
+ docker run --rm --entrypoint /bin/bash "$REF" -lc 'if find /app -maxdepth 6 -name "*.sqlite" -o -name "*.db" | grep -q .; then echo "Found SQLite DB in image"; exit 1; fi'
136
+ echo "OK: no baked SQLite DB"
137
+
138
+ - name: Inspect multi-arch manifest (release tag)
139
+ if: always()
140
+ shell: bash
141
+ run: |
142
+ echo "Inspecting v${SEMVER}…"
143
+ docker buildx imagetools inspect "${IMAGE}:v${SEMVER}"
144
+ if [ "${{ github.event_name }}" = "release" ]; then
145
+ echo "Inspecting latest…"
146
+ docker buildx imagetools inspect "${IMAGE}:latest"
147
+ fi
.github/workflows/ghcr.yml ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: 📦 Publish Docker (GHCR)
2
+
3
+ on:
4
+ release:
5
+ types: [published]
6
+ workflow_dispatch:
7
+ inputs:
8
+ version:
9
+ description: "Release tag (e.g., v1.2.3 or 1.2.3)"
10
+ required: true
11
+
12
+ permissions:
13
+ contents: read
14
+ packages: write
15
+
16
+ concurrency:
17
+ group: ghcr-publish-a2a-validator
18
+ cancel-in-progress: true
19
+
20
+ jobs:
21
+ build-and-push:
22
+ name: Build & Push (GHCR)
23
+ runs-on: ubuntu-latest
24
+
25
+ steps:
26
+ - name: Checkout
27
+ uses: actions/checkout@v4
28
+
29
+ # Normalize version from release tag or manual input
30
+ - name: Derive release version
31
+ id: version
32
+ shell: bash
33
+ run: |
34
+ if [ "${{ github.event_name }}" = "release" ]; then
35
+ RAW="${GITHUB_REF#refs/tags/}"
36
+ else
37
+ RAW="${{ github.event.inputs.version }}"
38
+ fi
39
+ if [ -z "$RAW" ]; then
40
+ echo "Version not provided."; exit 1
41
+ fi
42
+ if [[ "$RAW" =~ ^v ]]; then
43
+ RELEASE_TAG="$RAW"
44
+ SEMVER="${RAW#v}"
45
+ else
46
+ RELEASE_TAG="v$RAW"
47
+ SEMVER="$RAW"
48
+ fi
49
+ echo "RELEASE_TAG=$RELEASE_TAG" >> $GITHUB_ENV
50
+ echo "SEMVER=$SEMVER" >> $GITHUB_ENV
51
+ echo "SHORT_SHA=${GITHUB_SHA::7}" >> $GITHUB_ENV
52
+ echo "BUILD_DATE=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_ENV
53
+ echo "Resolved RELEASE_TAG=${RELEASE_TAG}, SEMVER=${SEMVER}, SHORT_SHA=${SHORT_SHA}"
54
+
55
+ # ghcr.io requires lowercase owner in the image path
56
+ - name: Compute image name (lowercase)
57
+ id: img
58
+ shell: bash
59
+ run: |
60
+ OWNER_LC="${GITHUB_REPOSITORY_OWNER,,}"
61
+ IMAGE="ghcr.io/${OWNER_LC}/a2a-validator"
62
+ echo "IMAGE=$IMAGE" >> $GITHUB_ENV
63
+ echo "Image: $IMAGE"
64
+
65
+ - name: Set up QEMU (multi-arch)
66
+ uses: docker/setup-qemu-action@v3
67
+
68
+ - name: Set up Docker Buildx
69
+ uses: docker/setup-buildx-action@v3
70
+
71
+ - name: GHCR login
72
+ uses: docker/login-action@v3
73
+ with:
74
+ registry: ghcr.io
75
+ username: ${{ github.actor }}
76
+ password: ${{ secrets.GITHUB_TOKEN }}
77
+
78
+ - name: Docker metadata (tags & labels)
79
+ id: meta
80
+ uses: docker/metadata-action@v5
81
+ with:
82
+ images: ${{ env.IMAGE }}
83
+ flavor: |
84
+ latest=false
85
+ tags: |
86
+ # stable semver tags (always)
87
+ type=raw,value=v${{ env.SEMVER }}
88
+ type=semver,pattern={{version}},value=${{ env.SEMVER }}
89
+ type=semver,pattern={{major}}.{{minor}},value=${{ env.SEMVER }}
90
+ type=semver,pattern={{major}},value=${{ env.SEMVER }}
91
+ # short sha tag (always)
92
+ type=raw,value=sha-${{ env.SHORT_SHA }}
93
+ # latest only on release
94
+ type=raw,value=latest,enable=${{ github.event_name == 'release' }}
95
+ labels: |
96
+ org.opencontainers.image.title=a2a-validator
97
+ org.opencontainers.image.description=A2A Validator — web inspector & debugger for A2A agents
98
+ org.opencontainers.image.url=https://github.com/${{ github.repository }}
99
+ org.opencontainers.image.source=https://github.com/${{ github.repository }}
100
+ org.opencontainers.image.version=${{ env.SEMVER }}
101
+ org.opencontainers.image.revision=${{ github.sha }}
102
+ org.opencontainers.image.created=${{ env.BUILD_DATE }}
103
+
104
+ - name: Build & push (GHCR)
105
+ id: build
106
+ uses: docker/build-push-action@v6
107
+ with:
108
+ context: .
109
+ file: ./Dockerfile
110
+ push: true
111
+ platforms: linux/amd64,linux/arm64
112
+ tags: ${{ steps.meta.outputs.tags }}
113
+ labels: ${{ steps.meta.outputs.labels }}
114
+ cache-from: type=gha
115
+ cache-to: type=gha,mode=max
116
+ build-args: |
117
+ BUILD_VERSION=${{ env.SEMVER }}
118
+ BUILD_COMMIT=${{ github.sha }}
119
+ BUILD_DATE=${{ env.BUILD_DATE }}
120
+
121
+ # Guard 1: The image must NOT contain a baked /app/.env
122
+ - name: Sanity guard — no baked .env
123
+ shell: bash
124
+ run: |
125
+ REF="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)"
126
+ docker run --rm --entrypoint /bin/bash "$REF" -lc 'test ! -f /app/.env'
127
+ echo "OK: no baked /app/.env"
128
+
129
+ # Guard 2: The image must NOT contain a SQLite db (e.g. *.sqlite or *.db)
130
+ - name: Sanity guard — no baked SQLite DB
131
+ shell: bash
132
+ run: |
133
+ REF="$(echo "${{ steps.meta.outputs.tags }}" | head -n1)"
134
+ docker run --rm --entrypoint /bin/bash "$REF" -lc 'if find /app -maxdepth 6 -name "*.sqlite" -o -name "*.db" | grep -q .; then echo "Found SQLite DB in image"; exit 1; fi'
135
+ echo "OK: no baked SQLite DB"
136
+
137
+ - name: Inspect multi-arch manifest (release tag)
138
+ if: always()
139
+ shell: bash
140
+ run: |
141
+ echo "Inspecting v${SEMVER}…"
142
+ docker buildx imagetools inspect "${IMAGE}:v${SEMVER}"
143
+ if [ "${{ github.event_name }}" = "release" ]; then
144
+ echo "Inspecting latest…"
145
+ docker buildx imagetools inspect "${IMAGE}:latest"
146
+ fi
README.md CHANGED
@@ -59,6 +59,59 @@ curl -s -X POST localhost:7860/agent-card \
59
  -d '{"url":"http://localhost:8080/","sid":"test"}' | jq
60
  ```
61
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  -----
63
 
64
  ## 🛠️ How It Works
 
59
  -d '{"url":"http://localhost:8080/","sid":"test"}' | jq
60
  ```
61
 
62
+ ## Installation (Docker) — pull from Docker Hub or GHCR
63
+
64
+ You can run A2A Validator as a single container. Choose your preferred registry, pull the image, and map a port.
65
+
66
+ > Replace placeholders with your image path and tag:
67
+ >
68
+ > * Docker Hub: `docker.io/russlanmv/a2a-validator`
69
+ > * GHCR: `ghcr.io/<owner>/a2a-validator`
70
+
71
+ ### Option 1 — Docker Hub
72
+
73
+ ```bash
74
+ # Pull
75
+ docker pull docker.io/ruslanmv/a2a-validator
76
+
77
+ # Run (maps host 7860 → container 7860)
78
+ docker run --rm -p 7860:7860 docker.io/ruslanmv/a2a-validator
79
+ ```
80
+
81
+ ### Option 2 — GitHub Container Registry (GHCR)
82
+
83
+ If needed, authenticate first:
84
+
85
+ ```bash
86
+ echo "$GITHUB_TOKEN" | docker login ghcr.io -u <github-username> --password-stdin
87
+ ```
88
+
89
+ Then pull and run:
90
+
91
+ ```bash
92
+ docker pull ghcr.io/<owner>/a2a-validator
93
+
94
+ docker run --rm -p 7860:7860 ghcr.io/ruslanmv/a2a-validator
95
+ ```
96
+
97
+ ### Quick smoke test
98
+
99
+ With the container running locally:
100
+
101
+ ```bash
102
+ # Open the UI
103
+ # http://localhost:7860/validator
104
+
105
+ # Optional: test the card endpoint
106
+ curl -s -X POST http://localhost:7860/agent-card \
107
+ -H 'content-type: application/json' \
108
+ -d '{"url":"http://localhost:8080/","sid":"test"}' | jq
109
+ ```
110
+
111
+ To stop it, press `Ctrl+C` (foreground) or `docker stop <container-id>` if you ran it detached.
112
+
113
+
114
+
115
  -----
116
 
117
  ## 🛠️ How It Works