Skip to content

Commit f23a689

Browse files
authored
feat: Server compliance audit through a website (#54)
Closes #8
1 parent da32059 commit f23a689

File tree

4 files changed

+289
-0
lines changed

4 files changed

+289
-0
lines changed

.github/workflows/website.yml

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: Website
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
8+
jobs:
9+
inject-audits:
10+
name: Inject audits
11+
runs-on: ubuntu-latest
12+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
13+
steps:
14+
- name: Checkout
15+
uses: actions/checkout@v3
16+
- name: Set up node
17+
uses: actions/setup-node@v3
18+
with:
19+
node-version: 18
20+
cache: yarn
21+
- name: Install
22+
run: yarn install --immutable
23+
- name: Build
24+
run: yarn build:umd
25+
- name: Inject
26+
run: node scripts/inject-audits-website.mjs
27+
- name: Upload website
28+
uses: actions/upload-pages-artifact@v1
29+
with:
30+
path: website
31+
32+
deploy:
33+
name: Deploy
34+
runs-on: ubuntu-latest
35+
if: "!contains(github.event.head_commit.message, '[skip ci]')"
36+
needs: [inject-audits]
37+
permissions:
38+
pages: write
39+
id-token: write
40+
concurrency:
41+
group: website-deploy
42+
cancel-in-progress: true
43+
environment:
44+
name: github-pages
45+
url: ${{ steps.deployment.outputs.page_url }}
46+
steps:
47+
- name: Checkout
48+
uses: actions/checkout@v3
49+
- name: Set up pages
50+
uses: actions/configure-pages@v3
51+
- name: Deploy
52+
id: deployment
53+
uses: actions/deploy-pages@v1

scripts/inject-audits-website.mjs

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import fs from 'fs/promises';
2+
import path from 'path';
3+
4+
async function main() {
5+
const openMark = '<!-- <graphql-http-audits.min.js> -->';
6+
const closeMark = '<!-- </graphql-http-audits.min.js> -->';
7+
8+
const index = (
9+
await fs.readFile(path.join('website', 'index.html'))
10+
).toString();
11+
const script = (
12+
await fs.readFile(path.join('umd', 'graphql-http-audits.min.js'))
13+
).toString();
14+
15+
await fs.writeFile(
16+
path.join('website', 'index.html'),
17+
index.replace(
18+
new RegExp(`${openMark}.+?${closeMark}`, 's'),
19+
// match the expected indentation in index.html
20+
`${openMark}
21+
<script>
22+
// prettier-ignore
23+
${
24+
// last character is a new line, remove it
25+
script.slice(0, -1)
26+
}
27+
</script>
28+
${closeMark}`,
29+
),
30+
);
31+
}
32+
33+
main().catch((err) => {
34+
console.error(err);
35+
process.exit(1);
36+
});

website/favicon.ico

11.7 KB
Binary file not shown.

website/index.html

+200
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
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+
7+
<link rel="icon" type="image/x-icon" href="favicon.ico" />
8+
<title>graphql-http</title>
9+
<meta
10+
name="description"
11+
content="Simple, pluggable, zero-dependency, GraphQL over HTTP spec compliant server, client and audit suite."
12+
/>
13+
14+
<style>
15+
*,
16+
*:before,
17+
*:after {
18+
box-sizing: border-box;
19+
}
20+
body {
21+
/* use system font */
22+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
23+
Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
24+
'Segoe UI Symbol';
25+
}
26+
27+
input {
28+
padding: 0.5em;
29+
font-size: 1em;
30+
width: 100%;
31+
}
32+
button {
33+
cursor: pointer;
34+
font-size: 1em;
35+
}
36+
37+
#audit-server-form {
38+
max-width: 512px;
39+
margin: 0 auto;
40+
}
41+
fieldset {
42+
padding: 1em;
43+
}
44+
45+
#report {
46+
max-width: 1024px;
47+
margin: 2em auto;
48+
padding: 2em;
49+
border: 2px solid grey;
50+
}
51+
#report.hidden {
52+
display: none;
53+
}
54+
#report.auditing {
55+
color: grey;
56+
background-color: lightgrey;
57+
text-align: center;
58+
}
59+
#report.error {
60+
color: red;
61+
border-color: red;
62+
}
63+
li {
64+
margin-bottom: 0.5em;
65+
}
66+
pre {
67+
border: 1px solid grey;
68+
padding: 1em;
69+
margin: 0;
70+
white-space: pre-wrap;
71+
word-wrap: break-word;
72+
}
73+
summary {
74+
cursor: pointer;
75+
}
76+
77+
footer {
78+
text-align: center;
79+
margin-bottom: 2em;
80+
}
81+
82+
.tip {
83+
color: grey;
84+
}
85+
</style>
86+
87+
<!-- <graphql-http-audits.min.js> -->
88+
<!-- the audits script will be injected as a part of the website deployment action -->
89+
<!-- </graphql-http-audits.min.js> -->
90+
</head>
91+
<body>
92+
<main>
93+
<h1 style="text-align: center">
94+
<a href="https://github.com/graphql/graphql-http">graphql-http</a>
95+
</h1>
96+
<p style="text-align: center; color: grey">
97+
Simple, pluggable, zero-dependency, GraphQL over HTTP spec compliant
98+
server, client and audit suite.
99+
</p>
100+
101+
<br />
102+
103+
<form id="audit-server-form" name="audit-server">
104+
<fieldset>
105+
<legend>
106+
Check for
107+
<a href="https://graphql.github.io/graphql-over-http/"
108+
>GraphQL over HTTP spec</a
109+
>
110+
compliance
111+
</legend>
112+
<div>
113+
<label for="url">URL of server to audit:</label>
114+
<br />
115+
<input id="url" type="url" name="url" required autofocus />
116+
<br />
117+
<small
118+
>Please make sure that
119+
<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"
120+
>CORS</a
121+
>
122+
allows this origin on your server.</small
123+
>
124+
</div>
125+
<br />
126+
<div style="text-align: right">
127+
<button type="submit">Audit</button>
128+
</div>
129+
</fieldset>
130+
</form>
131+
132+
<div id="report" class="hidden"></div>
133+
134+
<p style="text-align: center">
135+
<small class="tip"
136+
><b>💡 Tip:</b> Save this website and use it as a portable offline
137+
compliance checker.</small
138+
>
139+
</p>
140+
141+
<footer>
142+
<small>
143+
<a href="https://roadmap.sh/graphql">Learn GraphQL</a>
144+
|
145+
<a href="https://graphql.github.io/graphql-over-http/"
146+
>GraphQL over HTTP spec</a
147+
>
148+
|
149+
<a href="https://bundlephobia.com/package/graphql-http"
150+
>Bundlephobia (package size)</a
151+
>
152+
|
153+
<a href="https://github.com/graphql/graphql-http">GitHub</a>
154+
|
155+
<a href="https://www.npmjs.com/package/graphql-http">npm</a>
156+
</small>
157+
</footer>
158+
</main>
159+
160+
<script>
161+
const params = new URLSearchParams(window.location.search);
162+
const url = params.get('url');
163+
if (url) {
164+
const urlInput = document.getElementById('url');
165+
urlInput.setAttribute('value', url);
166+
urlInput.setAttribute('disabled', true);
167+
168+
const reportDiv = document.getElementById('report');
169+
reportDiv.classList.remove('hidden');
170+
reportDiv.classList.add('auditing');
171+
reportDiv.innerHTML = '⏳ Auditing...';
172+
173+
graphqlHttpAudits
174+
.auditServer({ url })
175+
.then((results) =>
176+
graphqlHttpAudits
177+
.renderAuditResultsToHTML(results)
178+
.then((html) => (reportDiv.innerHTML = html)),
179+
)
180+
.catch((err) => {
181+
console.error('Problem while auditing server', err);
182+
reportDiv.classList.add('error');
183+
reportDiv.innerHTML = `
184+
<small class="tip"><b>💡 Tip:</b> Open the console to see more details about the error.</small>
185+
<br /><br />
186+
187+
<pre style="border: 0; padding: 0">${
188+
err instanceof Error
189+
? err.message + '\n\n' + err.stack
190+
: JSON.stringify(err, null, ' ')
191+
}</pre>`;
192+
})
193+
.finally(() => {
194+
urlInput.removeAttribute('disabled');
195+
reportDiv.classList.remove('auditing');
196+
});
197+
}
198+
</script>
199+
</body>
200+
</html>

0 commit comments

Comments
 (0)