Skip to content

Commit 718d4e5

Browse files
lapc506claude
andcommitted
feat: initial scaffold of DojoCodingLabs Startups Android Marketplace
F-Droid-compatible repository for Android apps from startups incubated or accelerated through DojoCodingLabs hackathons and DojoOS Launchpad. Documentation: - docs/ARCHITECTURE.md — full technical design, hosting, pipeline, security - docs/KEEP_ANDROID_OPEN.md — impact assessment of Google's Developer Verification Program (Sept 2026) and resilience strategy - docs/SUBMISSION_GUIDE.md — step-by-step guide for startup developers Infrastructure: - GitHub Actions: validate-submission.yml (APK signature + metadata lint) - GitHub Actions: deploy-repo.yml (fdroidserver update + Vercel deploy) - vercel.json — security headers following dojo-os pattern - config.yml — fdroidserver repo configuration - Issue/PR templates for app submissions Hosting: Vercel CDN with HSTS, immutable APK caching, 5min index TTL. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
0 parents  commit 718d4e5

File tree

14 files changed

+1104
-0
lines changed

14 files changed

+1104
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
name: App Submission
2+
description: Submit a new app to the DojoCodingLabs Startups Marketplace
3+
title: "[Submission] "
4+
labels: ["submission", "needs-review"]
5+
body:
6+
- type: markdown
7+
attributes:
8+
value: |
9+
## App Submission
10+
11+
Thank you for submitting your app to the DojoCodingLabs Startups Android Marketplace.
12+
Please fill out the information below. A maintainer will review your submission.
13+
14+
- type: input
15+
id: package-name
16+
attributes:
17+
label: Package name
18+
description: "Android package name (e.g., com.yourstartup.app)"
19+
placeholder: "com.example.app"
20+
validations:
21+
required: true
22+
23+
- type: input
24+
id: app-name
25+
attributes:
26+
label: App name
27+
description: "Display name for the marketplace"
28+
placeholder: "My Startup App"
29+
validations:
30+
required: true
31+
32+
- type: input
33+
id: version
34+
attributes:
35+
label: Version
36+
description: "Version name and code (e.g., 1.0.0 / versionCode 1)"
37+
placeholder: "1.0.0 (1)"
38+
validations:
39+
required: true
40+
41+
- type: input
42+
id: source-code
43+
attributes:
44+
label: Source code URL
45+
description: "GitHub/GitLab/Codeberg repo URL (recommended)"
46+
placeholder: "https://github.com/yourstartup/app"
47+
48+
- type: input
49+
id: license
50+
attributes:
51+
label: License
52+
description: "SPDX identifier (e.g., MIT, GPL-3.0, Apache-2.0)"
53+
placeholder: "MIT"
54+
validations:
55+
required: true
56+
57+
- type: dropdown
58+
id: dojo-program
59+
attributes:
60+
label: DojoCodingLabs program
61+
description: "How is your startup connected to DojoCodingLabs?"
62+
options:
63+
- DojoOS Launchpad
64+
- DojoCodingLabs Hackathon
65+
- DojoCodingLabs Accelerator
66+
- Other (specify below)
67+
validations:
68+
required: true
69+
70+
- type: input
71+
id: dojo-program-details
72+
attributes:
73+
label: Program details
74+
description: "Hackathon name/date, Launchpad cohort, or other details"
75+
placeholder: "Hackathon 2026-Q1"
76+
77+
- type: dropdown
78+
id: toolkit
79+
attributes:
80+
label: Built with flutter-go-to-market-toolkit?
81+
description: "Did you use the toolkit for your release process?"
82+
options:
83+
- "Yes"
84+
- "No"
85+
- "Partially"
86+
87+
- type: textarea
88+
id: description
89+
attributes:
90+
label: App description
91+
description: "Brief description for the marketplace listing"
92+
placeholder: "What does your app do? Who is it for?"
93+
validations:
94+
required: true
95+
96+
- type: textarea
97+
id: pr-link
98+
attributes:
99+
label: Pull Request
100+
description: "Link to your PR with the APK and metadata (if already created)"
101+
placeholder: "https://github.com/DojoCodingLabs/startups-android-marketplace/pull/N"
102+
103+
- type: checkboxes
104+
id: checklist
105+
attributes:
106+
label: Submission checklist
107+
options:
108+
- label: "APK is signed with my release keystore"
109+
required: true
110+
- label: "I created a metadata YAML file following the template"
111+
required: true
112+
- label: "I have the rights to distribute this app"
113+
required: true
114+
- label: "The app does not contain malware or harmful content"
115+
required: true

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
## App Submission
2+
3+
**Package name:** `com.example.app`
4+
**Version:** 1.0.0 (versionCode 1)
5+
**DojoCodingLabs program:** Hackathon 2026-Q1 / Launchpad / Accelerator
6+
7+
## Checklist
8+
9+
- [ ] APK added to `apks/<package-name>/`
10+
- [ ] Metadata YAML created at `metadata/<package-name>.yml`
11+
- [ ] APK is signed with my release keystore
12+
- [ ] Metadata has all required fields (Categories, License, AuthorName, AutoName, Description)
13+
- [ ] CurrentVersion and CurrentVersionCode match the APK
14+
- [ ] Source code URL provided (recommended)
15+
16+
## For Updates
17+
18+
- [ ] New APK added (same signing key as previous version)
19+
- [ ] CurrentVersion and CurrentVersionCode bumped in metadata
20+
- [ ] Changelog provided below
21+
22+
## Changes
23+
24+
<!-- Describe what the app does or what changed in this update -->

.github/workflows/deploy-repo.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
name: Deploy F-Droid Repo
2+
3+
on:
4+
push:
5+
branches: [main]
6+
paths:
7+
- 'apks/**'
8+
- 'metadata/**'
9+
- 'config.yml'
10+
workflow_dispatch:
11+
12+
jobs:
13+
build-and-deploy:
14+
name: Build repo index and deploy
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- name: Setup Python
21+
uses: actions/setup-python@v5
22+
with:
23+
python-version: '3.12'
24+
25+
- name: Install fdroidserver
26+
run: pip install fdroidserver
27+
28+
- name: Setup Android SDK
29+
uses: android-actions/setup-android@v3
30+
31+
- name: Restore repo signing keystore
32+
run: |
33+
echo "$FDROID_KEYSTORE_BASE64" | base64 -d > keystore.p12
34+
env:
35+
FDROID_KEYSTORE_BASE64: ${{ secrets.FDROID_KEYSTORE_BASE64 }}
36+
37+
- name: Copy APKs to repo directory
38+
run: |
39+
mkdir -p repo
40+
find apks -name '*.apk' -exec cp {} repo/ \;
41+
ls -la repo/*.apk 2>/dev/null || echo "No APKs found"
42+
43+
- name: Generate repo index
44+
run: fdroid update --create-metadata --verbose
45+
env:
46+
FDROID_KEY_STORE_PASS: ${{ secrets.FDROID_KEY_STORE_PASS }}
47+
FDROID_KEY_PASS: ${{ secrets.FDROID_KEY_PASS }}
48+
49+
- name: Verify repo index
50+
run: |
51+
test -f repo/index-v2.json || { echo "FAIL: index not generated"; exit 1; }
52+
python3 -c "
53+
import json
54+
data = json.load(open('repo/index-v2.json'))
55+
count = len(data.get('packages', {}))
56+
print(f'Apps in repo: {count}')
57+
"
58+
59+
- name: Deploy to Vercel
60+
uses: amondnet/vercel-action@v25
61+
with:
62+
vercel-token: ${{ secrets.VERCEL_TOKEN }}
63+
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
64+
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
65+
vercel-args: '--prod'
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Validate App Submission
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
paths:
7+
- 'apks/**'
8+
- 'metadata/**'
9+
10+
jobs:
11+
validate:
12+
name: Validate APK and metadata
13+
runs-on: ubuntu-latest
14+
15+
steps:
16+
- uses: actions/checkout@v4
17+
with:
18+
fetch-depth: 0
19+
20+
- name: Setup Android SDK
21+
uses: android-actions/setup-android@v3
22+
23+
- name: Find new APKs
24+
id: apks
25+
run: |
26+
APKS=$(git diff --name-only origin/main...HEAD -- 'apks/*.apk' || true)
27+
if [ -z "$APKS" ]; then
28+
echo "No new APKs found in this PR"
29+
echo "has_apks=false" >> "$GITHUB_OUTPUT"
30+
else
31+
echo "Found APKs:"
32+
echo "$APKS"
33+
echo "has_apks=true" >> "$GITHUB_OUTPUT"
34+
# Write APK list to file to avoid injection via filenames
35+
echo "$APKS" > /tmp/apk_list.txt
36+
fi
37+
38+
- name: Verify APK signatures
39+
if: steps.apks.outputs.has_apks == 'true'
40+
run: |
41+
while IFS= read -r apk; do
42+
if [ -f "$apk" ]; then
43+
echo "=== Verifying: $apk ==="
44+
apksigner verify --print-certs "$apk"
45+
if [ $? -ne 0 ]; then
46+
echo "FAIL: $apk signature verification failed"
47+
exit 1
48+
fi
49+
echo "PASS: Signature valid"
50+
fi
51+
done < /tmp/apk_list.txt
52+
53+
- name: Extract APK metadata
54+
if: steps.apks.outputs.has_apks == 'true'
55+
run: |
56+
while IFS= read -r apk; do
57+
if [ -f "$apk" ]; then
58+
echo "=== Metadata: $apk ==="
59+
aapt2 dump badging "$apk" | head -5
60+
echo "---"
61+
echo "Permissions:"
62+
aapt2 dump permissions "$apk"
63+
echo ""
64+
fi
65+
done < /tmp/apk_list.txt
66+
67+
- name: Validate metadata YAML
68+
run: |
69+
pip install pyyaml
70+
71+
for yml in metadata/*.yml; do
72+
if [ -f "$yml" ]; then
73+
echo "=== Validating: $yml ==="
74+
python3 << 'PYEOF'
75+
import yaml, sys, os
76+
77+
required = ['Categories', 'License', 'AuthorName', 'AutoName', 'Description', 'CurrentVersion', 'CurrentVersionCode']
78+
yml_path = os.environ.get('YML_FILE', '')
79+
80+
with open(yml_path) as f:
81+
data = yaml.safe_load(f)
82+
83+
missing = [field for field in required if field not in data]
84+
if missing:
85+
print(f'FAIL: Missing required fields: {missing}')
86+
sys.exit(1)
87+
88+
print('PASS: All required fields present')
89+
print(f' App: {data["AutoName"]}')
90+
print(f' Version: {data["CurrentVersion"]} ({data["CurrentVersionCode"]})')
91+
print(f' License: {data["License"]}')
92+
print(f' Author: {data["AuthorName"]}')
93+
PYEOF
94+
fi
95+
done
96+
env:
97+
YML_FILE: ${{ '' }}
98+
99+
- name: Summary
100+
if: always()
101+
run: |
102+
echo "## Submission Validation Results" >> "$GITHUB_STEP_SUMMARY"
103+
echo "" >> "$GITHUB_STEP_SUMMARY"
104+
echo "Validation complete. Check step logs for details." >> "$GITHUB_STEP_SUMMARY"

.gitignore

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
# F-Droid repo output (generated by fdroidserver)
2+
repo/
3+
tmp/
4+
unsigned/
5+
archive/
6+
7+
# Signing keys (NEVER commit)
8+
*.jks
9+
*.keystore
10+
*.p12
11+
keystore.properties
12+
13+
# Vercel
14+
.vercel/
15+
16+
# OS
17+
.DS_Store
18+
Thumbs.db
19+
20+
# Python (fdroidserver)
21+
__pycache__/
22+
*.pyc
23+
.venv/

0 commit comments

Comments
 (0)