Skip to content

Commit b14a624

Browse files
committed
Merge v2-static-site: Complete overhaul with HMAC-SHA256 signatures and Human model support
2 parents aa28564 + 6d1b439 commit b14a624

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+10471
-6032
lines changed

.github/workflows/deploy.yml

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches: [ main, v2-static-site ]
6+
pull_request:
7+
branches: [ main ]
8+
workflow_dispatch:
9+
10+
permissions:
11+
contents: read
12+
pages: write
13+
id-token: write
14+
15+
concurrency:
16+
group: "pages"
17+
cancel-in-progress: false
18+
19+
jobs:
20+
validate-attestations:
21+
runs-on: ubuntu-latest
22+
steps:
23+
- name: Checkout
24+
uses: actions/checkout@v4
25+
26+
- name: Setup Node.js
27+
uses: actions/setup-node@v4
28+
with:
29+
node-version: '20'
30+
31+
- name: Validate attestation files
32+
run: |
33+
# Validate all attestation JSON files
34+
for file in attestations/v2/*.json; do
35+
if [ -f "$file" ]; then
36+
echo "Validating $file..."
37+
node -e "
38+
const fs = require('fs');
39+
const content = fs.readFileSync('$file', 'utf8');
40+
try {
41+
const attestation = JSON.parse(content);
42+
// Basic validation
43+
if (!attestation.version || !attestation.id || !attestation.content_hash) {
44+
throw new Error('Missing required fields');
45+
}
46+
console.log(' Valid attestation');
47+
} catch (e) {
48+
console.error(' Invalid attestation:', e.message);
49+
process.exit(1);
50+
}
51+
"
52+
fi
53+
done
54+
55+
build-stats:
56+
runs-on: ubuntu-latest
57+
needs: validate-attestations
58+
steps:
59+
- name: Checkout
60+
uses: actions/checkout@v4
61+
62+
- name: Generate statistics
63+
run: |
64+
# Count attestations and generate stats
65+
echo "Generating attestation statistics..."
66+
67+
# Create a stats.json file
68+
node -e "
69+
const fs = require('fs');
70+
const path = require('path');
71+
72+
// Count attestations
73+
let v1Count = 0;
74+
let v2Count = 0;
75+
const models = new Set();
76+
77+
// Count v2 attestations
78+
const v2Dir = 'attestations/v2';
79+
if (fs.existsSync(v2Dir)) {
80+
const files = fs.readdirSync(v2Dir);
81+
files.forEach(file => {
82+
if (file.endsWith('.json')) {
83+
v2Count++;
84+
try {
85+
const content = fs.readFileSync(path.join(v2Dir, file), 'utf8');
86+
const attestation = JSON.parse(content);
87+
if (attestation.model) {
88+
models.add(attestation.model);
89+
}
90+
} catch (e) {}
91+
}
92+
});
93+
}
94+
95+
// Count legacy attestations (directories named with numbers)
96+
for (let i = 1; i <= 999; i++) {
97+
if (fs.existsSync(String(i))) {
98+
v1Count++;
99+
}
100+
}
101+
102+
const stats = {
103+
total: v1Count + v2Count,
104+
v1: v1Count,
105+
v2: v2Count,
106+
models: models.size,
107+
lastUpdated: new Date().toISOString()
108+
};
109+
110+
fs.writeFileSync('static/stats.json', JSON.stringify(stats, null, 2));
111+
console.log('Stats generated:', stats);
112+
"
113+
114+
- name: Upload stats artifact
115+
uses: actions/upload-artifact@v4
116+
with:
117+
name: stats
118+
path: static/stats.json
119+
120+
deploy:
121+
environment:
122+
name: github-pages
123+
url: ${{ steps.deployment.outputs.page_url }}
124+
runs-on: ubuntu-latest
125+
needs: build-stats
126+
steps:
127+
- name: Checkout
128+
uses: actions/checkout@v4
129+
130+
- name: Download stats artifact
131+
uses: actions/download-artifact@v4
132+
with:
133+
name: stats
134+
path: static/
135+
136+
- name: Setup Pages
137+
uses: actions/configure-pages@v4
138+
139+
- name: Upload artifact
140+
uses: actions/upload-pages-artifact@v3
141+
with:
142+
path: '.'
143+
144+
- name: Deploy to GitHub Pages
145+
id: deployment
146+
uses: actions/deploy-pages@v4
147+
148+
verify-deployment:
149+
runs-on: ubuntu-latest
150+
needs: deploy
151+
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
152+
steps:
153+
- name: Wait for deployment
154+
run: sleep 30
155+
156+
- name: Verify deployment
157+
run: |
158+
# Test key endpoints
159+
urls=(
160+
"https://attest.ink/"
161+
"https://attest.ink/create/"
162+
"https://attest.ink/view/"
163+
"https://attest.ink/developers/"
164+
"https://attest.ink/protocol/"
165+
"https://attest.ink/static/badge-renderer.js"
166+
"https://attest.ink/static/attestation-tool.js"
167+
)
168+
169+
for url in "${urls[@]}"; do
170+
echo "Testing $url..."
171+
if curl -f -s -o /dev/null "$url"; then
172+
echo " $url is accessible"
173+
else
174+
echo " $url failed"
175+
exit 1
176+
fi
177+
done
178+
179+
echo "All endpoints verified successfully!"

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.DS_Store

404.html

Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>404 - Page Not Found | attest.ink</title>
7+
<meta name="description" content="Page not found. The attestation you're looking for might have moved or doesn't exist.">
8+
<link rel="icon" type="image/svg+xml" href="/assets/logo/favicon.svg">
9+
<link rel="icon" type="image/x-icon" href="/assets/favicon.ico">
10+
<link rel="manifest" href="/assets/site.webmanifest">
11+
<meta name="theme-color" content="#111827">
12+
<link rel="stylesheet" href="/static/style.css">
13+
<link rel="stylesheet" href="/static/badge-styles.css">
14+
<style>
15+
.error-container {
16+
text-align: center;
17+
padding: 60px 20px;
18+
min-height: 60vh;
19+
display: flex;
20+
flex-direction: column;
21+
justify-content: center;
22+
align-items: center;
23+
}
24+
25+
.error-code {
26+
font-size: 120px;
27+
color: var(--pixel-secondary);
28+
margin: 0;
29+
line-height: 1;
30+
text-shadow: 4px 4px 0 var(--shadow);
31+
animation: glitch 2s infinite;
32+
}
33+
34+
@keyframes glitch {
35+
0%, 100% { transform: translate(0); }
36+
20% { transform: translate(-2px, 2px); }
37+
40% { transform: translate(-2px, -2px); }
38+
60% { transform: translate(2px, 2px); }
39+
80% { transform: translate(2px, -2px); }
40+
}
41+
42+
.error-message {
43+
font-size: 32px;
44+
color: var(--pixel-primary);
45+
margin: 20px 0;
46+
text-transform: uppercase;
47+
}
48+
49+
.error-description {
50+
font-size: 20px;
51+
color: var(--text-secondary);
52+
margin: 20px 0 40px;
53+
max-width: 600px;
54+
}
55+
56+
.error-actions {
57+
display: flex;
58+
gap: 16px;
59+
flex-wrap: wrap;
60+
justify-content: center;
61+
}
62+
63+
.pixel-decoration {
64+
position: absolute;
65+
width: 8px;
66+
height: 8px;
67+
background: var(--pixel-accent);
68+
animation: float 3s ease-in-out infinite;
69+
}
70+
71+
.pixel-decoration:nth-child(1) {
72+
top: 10%;
73+
left: 10%;
74+
animation-delay: 0s;
75+
}
76+
77+
.pixel-decoration:nth-child(2) {
78+
top: 20%;
79+
right: 15%;
80+
animation-delay: 0.5s;
81+
}
82+
83+
.pixel-decoration:nth-child(3) {
84+
bottom: 30%;
85+
left: 20%;
86+
animation-delay: 1s;
87+
}
88+
89+
.pixel-decoration:nth-child(4) {
90+
bottom: 20%;
91+
right: 10%;
92+
animation-delay: 1.5s;
93+
}
94+
95+
@media (max-width: 768px) {
96+
.error-code {
97+
font-size: 80px;
98+
}
99+
100+
.error-message {
101+
font-size: 24px;
102+
}
103+
104+
.error-description {
105+
font-size: 18px;
106+
padding: 0 20px;
107+
}
108+
109+
.error-actions {
110+
flex-direction: column;
111+
width: 100%;
112+
max-width: 300px;
113+
}
114+
115+
.error-actions .btn {
116+
width: 100%;
117+
}
118+
}
119+
120+
@media (max-width: 480px) {
121+
.error-code {
122+
font-size: 60px;
123+
}
124+
125+
.error-message {
126+
font-size: 20px;
127+
}
128+
}
129+
</style>
130+
<script>
131+
// Prevent theme flicker by setting theme before render
132+
(function() {
133+
const saved = localStorage.getItem('theme');
134+
let theme = 'light';
135+
if (saved) {
136+
theme = saved;
137+
} else if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
138+
theme = 'dark';
139+
} else {
140+
const hour = new Date().getHours();
141+
if (hour >= 18 || hour < 6) {
142+
theme = 'dark';
143+
}
144+
}
145+
document.documentElement.setAttribute('data-theme', theme);
146+
})();
147+
</script>
148+
</head>
149+
<body>
150+
<button class="theme-toggle" id="theme-toggle" aria-label="Toggle theme">D</button>
151+
152+
<!-- Pixel decorations -->
153+
<div class="pixel-decoration"></div>
154+
<div class="pixel-decoration"></div>
155+
<div class="pixel-decoration"></div>
156+
<div class="pixel-decoration"></div>
157+
158+
<div class="container">
159+
<nav>
160+
<div class="nav-inner">
161+
<a href="/" class="logo">
162+
<img src="/assets/logo/circular-2-ai.svg" alt="attest.ink logo">
163+
<span>attest.ink</span>
164+
</a>
165+
<ul>
166+
<li><a href="/create/">Create</a></li>
167+
<li><a href="/verify/">Verify</a></li>
168+
<li class="dropdown">
169+
<span class="dropdown-toggle">More</span>
170+
<div class="dropdown-menu">
171+
<a href="/protocol/">Protocol</a>
172+
<a href="/showcase/">Badges</a>
173+
<a href="/examples/">Examples</a>
174+
<a href="/developers/">Developer Docs</a>
175+
<a href="/faq.html">FAQ</a>
176+
<a href="https://github.com/statusdothealth/attest.ink" target="_blank">GitHub</a>
177+
</div>
178+
</li>
179+
</ul>
180+
</div>
181+
</nav>
182+
183+
<main>
184+
<div class="error-container">
185+
<h1 class="error-code">404</h1>
186+
<h2 class="error-message">Page Not Found</h2>
187+
<p class="error-description">
188+
The attestation or page you're looking for might have been moved, deleted, or doesn't exist.
189+
Don't worry, you can create a new attestation or verify an existing one.
190+
</p>
191+
192+
<div class="error-actions">
193+
<a href="/" class="btn">Go Home</a>
194+
<a href="/create/" class="btn btn-secondary">Create Attestation</a>
195+
<a href="/verify/" class="btn btn-secondary">Verify Attestation</a>
196+
</div>
197+
</div>
198+
</main>
199+
200+
</div>
201+
202+
<script src="/static/theme.js"></script>
203+
<script src="/static/global-footer.js"></script>
204+
</body>
205+
</html>

0 commit comments

Comments
 (0)