The Docker build is running. Follow these steps once it completes:
# The build is running in the background
# You can check if it's done with:
docker images | grep gogs
# If you see the image, the build is complete
# Start Gogs and PostgreSQL
docker-compose -f docker-compose.test.yml up -d
# Check that containers are running
docker-compose -f docker-compose.test.yml ps
# Expected output:
# NAME STATUS PORTS
# gogs-test Up (healthy) 0.0.0.0:10022->22/tcp, 0.0.0.0:10080->3000/tcp
# gogs-test-postgres Up (healthy) 5432/tcp
# Follow Gogs logs
docker-compose -f docker-compose.test.yml logs -f gogs
# You should see:
# - Database migration messages
# - "Listen on http://0.0.0.0:3000"
# - The GPG keys table (gpg_key) being created
Open your browser and go to: http://localhost:10080
Complete the installation wizard with these settings:
Click Install Gogs
Check that the database migration created the GPG keys table:
# Access PostgreSQL
docker exec -it gogs-test-postgres psql -U gogs -d gogs
# Inside psql:
\dt # List all tables (should see gpg_key)
\d gpg_key # Describe the gpg_key table
SELECT * FROM version; # Check migration version (should be 23 or higher)
\q # Exit
Expected table structure:
Table "public.gpg_key"
Column | Type | Collation | Nullable | Default
---------------+------------------------+-----------+----------+------------------------------------
id | bigint | | not null | nextval('gpg_key_id_seq'::regclass)
owner_id | bigint | | not null |
key_id | character varying(16) | | not null |
fingerprint | character varying(40) | | not null |
content | text | | not null |
can_sign | boolean | | not null | false
can_encrypt | boolean | | not null | false
emails | text | | |
created_unix | bigint | | |
updated_unix | bigint | | |
expired_unix | bigint | | |
Save it as an environment variable:
export GOGS_TOKEN="your_token_here"
curl -H "Authorization: token $GOGS_TOKEN" \
http://localhost:10080/api/v1/user/gpg_keys
Expected: []
# Generate a test key (non-interactive)
gpg --batch --gen-key <<EOF
Key-Type: RSA
Key-Length: 2048
Subkey-Type: RSA
Subkey-Length: 2048
Name-Real: Test User
Name-Email: test@example.com
Expire-Date: 0
%no-protection
EOF
# List keys
gpg --list-keys
# Export public key
gpg --armor --export test@example.com > test-key.asc
# View the key
cat test-key.asc
curl -X POST \
-H "Authorization: token $GOGS_TOKEN" \
-H "Content-Type: application/json" \
-d "{\"armored_public_key\": \"$(cat test-key.asc | sed ':a;N;$!ba;s/\n/\\n/g')\"}" \
http://localhost:10080/api/v1/user/gpg_keys | jq
Expected response:
{
"id": 1,
"key_id": "ABCD1234567890EF",
"fingerprint": "1234567890ABCDEF1234567890ABCDEF12345678",
"primary_key_id": "ABCD1234567890EF",
"public_key": "-----BEGIN PGP PUBLIC KEY BLOCK-----\n...",
"emails": ["test@example.com"],
"can_sign": true,
"can_encrypt_comms": true,
"can_encrypt_storage": true,
"can_certify": true,
"created": "2025-11-01T22:00:00Z"
}
curl -H "Authorization: token $GOGS_TOKEN" \
http://localhost:10080/api/v1/user/gpg_keys | jq
Should now show your key!
# Configure git
git config --global user.name "Test User"
git config --global user.email "test@example.com"
git config --global user.signingkey $(gpg --list-secret-keys --keyid-format LONG test@example.com | grep sec | awk '{print $2}' | cut -d'/' -f2)
git config --global commit.gpgsign true
# Create a test repository via API
curl -X POST \
-H "Authorization: token $GOGS_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name":"gpg-test","description":"Testing GPG signatures","private":false}' \
http://localhost:10080/api/v1/user/repos
# Clone it
git clone http://localhost:10080/your-username/gpg-test.git
cd gpg-test
# Create a signed commit
echo "# GPG Test" > README.md
git add README.md
git commit -m "Initial commit - GPG signed"
# Verify signature locally
git log --show-signature -1
# Push to Gogs (enter your Gogs username and password)
git push origin main
# Check that the GPG key is stored
docker exec -it gogs-test-postgres psql -U gogs -d gogs -c \
"SELECT id, owner_id, key_id, fingerprint, can_sign, emails FROM gpg_key;"
# Should show your imported key
curl -H "Authorization: token $GOGS_TOKEN" \
http://localhost:10080/api/v1/user/gpg_keys/1 | jq
curl -X DELETE \
-H "Authorization: token $GOGS_TOKEN" \
http://localhost:10080/api/v1/user/gpg_keys/1
curl -H "Authorization: token $GOGS_TOKEN" \
http://localhost:10080/api/v1/user/gpg_keys | jq
Should return empty array []
# Check build logs
docker-compose -f docker-compose.test.yml logs gogs
# Rebuild from scratch
docker-compose -f docker-compose.test.yml build --no-cache
# Check all logs
docker-compose -f docker-compose.test.yml logs
# Check health status
docker-compose -f docker-compose.test.yml ps
# Verify PostgreSQL is running
docker-compose -f docker-compose.test.yml ps postgres
# Check PostgreSQL logs
docker-compose -f docker-compose.test.yml logs postgres
# Test connection
docker exec -it gogs-test-postgres psql -U gogs -d gogs -c "SELECT 1;"
# Validate key format
gpg --show-keys test-key.asc
# Check key is properly armored
head -1 test-key.asc # Should be: -----BEGIN PGP PUBLIC KEY BLOCK-----
tail -1 test-key.asc # Should be: -----END PGP PUBLIC KEY BLOCK-----
# Try exporting again
gpg --armor --export test@example.com > test-key.asc
docker-compose -f docker-compose.test.yml stop
docker-compose -f docker-compose.test.yml down
docker-compose -f docker-compose.test.yml down -v
✅ Backend Implementation Complete:
⚠️ UI Not Yet Implemented:
To add UI components, you would need to:
templates/user/settings/internal/route/user/For now, all functionality is accessible via the REST API!
TEST_GPG_VERIFICATION.mddocs/features/gpg_verification.mdHappy testing! 🎉