Document Version: 1.0 Last Updated: 2025-11-07 Prepared By: Testing & Documentation Agent Purpose: Pre-deployment security and quality assurance checklist
audit-log-YYYY-MM-DD.md) PUBLIC_DOCUSEAL_TEMPLATE_PROLIFIC set in production .env
echo $PUBLIC_DOCUSEAL_TEMPLATE_PROLIFIC (should return template ID) PUBLIC_DOCUSEAL_TEMPLATE_RECRUITEE set in production .env
echo $PUBLIC_DOCUSEAL_TEMPLATE_RECRUITEE PUBLIC_DOCUSEAL_API_URL points to production backend
https://api.yourpersonalai.net/create-submitterecho $PUBLIC_DOCUSEAL_API_URLcurl -X POST $PUBLIC_DOCUSEAL_API_URL (should return 400/401, not 404)No hardcoded secrets in source code
git grep -i "api_key\|secret\|password\|token" src/pages/getreal/.env (gitignored) .env file is NOT committed to version control
.env is in .gitignoregit check-ignore .env (should return .env)PID validation tested
5f8d7a3b → ✅ PASSab → ❌ FAILtest@user → ❌ FAIL<script>alert(1)</script> → ❌ FAILnode --test src/pages/getreal/__tests__/consent.test.jsEmail validation tested
[email protected] → ✅ PASS[email protected] → ❌ FAIL[email protected] → ❌ FAIL[email protected] → ❌ FAIL<script>@example.com → ❌ FAILnode --test src/pages/getreal/__tests__/consent.test.jsXSS prevention verified
<script>alert(1)</script> in PID/emailinnerHTML usage in code (use textContent instead)SQL injection prevention verified
'; DROP TABLE users; -- in PID/email// Run in browser console on /getreal/consent page
async function testRateLimit() {
for (let i = 1; i <= 6; i++) {
const response = await fetch('/api/create-submitter', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
template_id: 1228886,
prolific_pid: `test-${Date.now()}`,
}),
});
console.log(`Attempt ${i}:`, response.status, await response.text());
await new Promise((r) => setTimeout(r, 1000)); // 1s delay
}
}
testRateLimit();
Fetch timeout tested (15 seconds max)
HTTPS enforcement verified
https://yourpersonalai.net/getreal/consentcurl -I http://yourpersonalai.net/getreal/consent (expect 301/302)CORS headers verified (backend)
Access-Control-Allow-Origin: https://yourpersonalai.netcurl -I -X OPTIONS $PUBLIC_DOCUSEAL_API_URLOffline detection tested
Network timeout tested
400 Bad Request handled
curl -X POST $PUBLIC_DOCUSEAL_API_URL -d 'invalid'401 Unauthorized handled
403 Forbidden handled
404 Not Found handled
500 Internal Server Error handled
No stack traces exposed to users
Error: ... at line XEmail masking in console logs verified
[email protected]j***@example.com (not full email)No PII in error messages
sessionStorage cleared on completion
No sensitive data in URL after redirect
?id=abc123 ✅ OK | [email protected] ❌ FAILData minimization verified
Right to be forgotten process documented
PRIVACY-POLICY.md or equivalentData retention policy defined
ARIA labels on progress indicators
role="progressbar" with aria-valuemin, aria-valuemax, aria-valuenow#cgScrollProgressScreen reader announcements tested
role="status" aria-live="polite" on status elementKeyboard navigation tested
Color contrast verified (4.5:1 minimum for text)
Focus indicators visible
:focus styles in CSSMemory leaks tested (Page Visibility API)
Event listeners cleaned up
window event listeners before/after form completiongetEventListeners(window)No excessive network requests
API request deduplication
Scroll tracking tested (desktop)
Scroll tracking tested (mobile)
Prolific flow tested
/getreal/consent?prolific_pid=test123/getreal/video-redirect?prolific_pid=test123&source=ProlificRecruitee flow tested
/getreal/[email protected]/getreal/[email protected]&source=Recruitee/getreal/video-redirect?<identifier>&source=<Prolific|Recruitee>Chrome/Edge tested (Windows 11)
Firefox tested (Windows 11)
Safari tested (macOS)
iOS Safari tested (iPhone 12+)
Chrome Android tested (Pixel 5+)
fetch, URLSearchParams, Promise supportDocuSeal form embedding tested
.cg-form-wrap container<docuseal-form> element created with correct data-srcDocuSeal script loaded
https://cdn.docuseal.com/js/form.js loads successfullyForm completion event tested
completed event firesBackend API tested (create submitter endpoint)
POST /create-submitter{
"template_id": 1228886,
"prolific_pid": "test123",
"source": "Prolific",
"completed_redirect_url": "/getreal/video-redirect?prolific_pid=test123&source=Prolific"
}
{
"ok": true,
"slug": "abc123xyz",
"redirect_url": "/getreal/video-redirect?prolific_pid=test123&source=Prolific"
}
API error responses handled
template_id)/getreal/[email protected]data-email="[email protected]" on <docuseal-form>/getreal/consent?prolific_pid=5f8d7a3bDebug logging disabled
CONFIG.debug = false in production buildgrep "debug: true" src/pages/getreal/consent.astro (should return nothing)Console errors checked
TypeScript errors resolved (if applicable)
npm run build/getreal/consent?prolific_pid=test123npm run test:lighthouse:mobile (if configured)Sentry configured (or equivalent)
.envError alerting tested
Note: These are backend responsibilities, verify with backend team.
Content-Security-Policy header set
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.docuseal.comcurl -I https://api.yourpersonalai.net/create-submitterX-Content-Type-Options header set
X-Content-Type-Options: nosniffX-Frame-Options header set
X-Frame-Options: DENY or SAMEORIGINStrict-Transport-Security header set
Strict-Transport-Security: max-age=31536000; includeSubDomainsReferrer-Policy header set
Referrer-Policy: strict-origin-when-cross-originREADME updated with setup instructions
API documentation complete
Privacy policy updated
Incident response plan documented
// Run in browser console on /getreal/consent page
async function testRateLimit() {
const pid = `test-${Date.now()}`;
for (let i = 1; i <= 6; i++) {
const response = await fetch('https://api.yourpersonalai.net/create-submitter', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
template_id: 1228886,
prolific_pid: pid,
source: 'Prolific',
completed_redirect_url: '/getreal/video-redirect',
}),
});
const data = await response.json();
console.log(`Attempt ${i}:`, response.status, data);
await new Promise((r) => setTimeout(r, 1000)); // 1s delay
}
}
testRateLimit();
// Test in browser console
const xssPayloads = [
'<script>alert("XSS")</script>',
'<img src=x onerror=alert(1)>',
'javascript:alert(1)',
'<svg/onload=alert(1)>',
'"><script>alert(1)</script>',
];
xssPayloads.forEach((payload) => {
const url = `/getreal/consent?prolific_pid=${encodeURIComponent(payload)}`;
console.log('Testing XSS:', url);
// Open in new tab and verify error message shown (payload not executed)
});
const sqlPayloads = ["'; DROP TABLE users; --", "1' OR '1'='1", "admin'--"];
sqlPayloads.forEach((payload) => {
const url = `/getreal/consent?prolific_pid=${encodeURIComponent(payload)}`;
console.log('Testing SQL injection:', url);
// Verify payload rejected by validation
});
End of Checklist
| Version | Date | Author | Changes |
|---|---|---|---|
| 1.0 | 2025-11-07 | Testing Agent | Initial checklist created |
src/pages/getreal/__tests__/consent.test.jsPRIVACY-POLICY.md (TODO)API-DOCUMENTATION.md (TODO)INCIDENT-RESPONSE.md (TODO)