Skip to content

Commit 537dc5a

Browse files
authored
Merge pull request #295 from Lissy93/upgrade/new-structure
Reliability improvments and fixes
2 parents 55d8657 + d5e8716 commit 537dc5a

175 files changed

Lines changed: 14799 additions & 11346 deletions

File tree

Some content is hidden

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

.config/eslint.config.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import eslintPluginAstro from 'eslint-plugin-astro';
2+
import tsParser from '@typescript-eslint/parser';
3+
4+
export default [
5+
...eslintPluginAstro.configs.recommended,
6+
{
7+
files: ['**/*.ts', '**/*.tsx'],
8+
languageOptions: {
9+
parser: tsParser,
10+
},
11+
},
12+
{
13+
ignores: ['dist/', 'node_modules/', '.astro/', '.netlify/', '.vercel/'],
14+
},
15+
];

.env renamed to .env.sample

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,29 @@
22
# Be sure to uncomment any line you populate
33
# Everything is optional, but some features won't work without external API access
44

5+
# Kill switch for the public/hosted instance
6+
# VITE_DISABLE_EVERYTHING='false'
7+
58
# API Keys for external services (backend)
69
GOOGLE_CLOUD_API_KEY=''
710
TORRENT_IP_API_KEY=''
811
SECURITY_TRAILS_API_KEY=''
9-
BUILT_WITH_API_KEY=''
1012
URL_SCAN_API_KEY=''
1113
TRANCO_USERNAME=''
1214
TRANCO_API_KEY=''
1315
CLOUDMERSIVE_API_KEY=''
14-
15-
# API Keys for external services (frontend)
16-
REACT_APP_SHODAN_API_KEY=''
17-
REACT_APP_WHO_API_KEY=''
16+
SHODAN_API_KEY=''
17+
WHO_API_KEY=''
1818

1919
# Configuration settings
2020
# CHROME_PATH='/usr/bin/chromium' # The path the the Chromium executable
2121
# PORT='3000' # Port to serve the API, when running server.js
2222
# DISABLE_GUI='false' # Disable the GUI, and only serve the API
23-
# API_TIMEOUT_LIMIT='10000' # The timeout limit for API requests, in milliseconds
23+
# PUBLIC_API_TIMEOUT_LIMIT='25000'# Timeout for API requests, in milliseconds
2424
# API_CORS_ORIGIN='*' # Enable CORS, by setting your allowed hostname(s) here
2525
# API_ENABLE_RATE_LIMIT='true' # Enable rate limiting for the API
2626
# REACT_APP_API_ENDPOINT='/api' # The endpoint for the API (can be local or remote)
2727
# ENABLE_ANALYTICS='false' # Enable Plausible hit counter for the frontend
28+
# BOSS_SERVER='false' # Marketing homepage (only used by official instance)
29+
# TRUST_PROXY='1' # Set if running behind a reverse proxy (Traefik, nginx, etc).
30+
# Use a number of hops (e.g. '1'), 'true', or a CIDR list.

.github/README.md

Lines changed: 148 additions & 414 deletions
Large diffs are not rendered by default.

.github/workflows/bump-and-tag.yml

Lines changed: 325 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,325 @@
1+
# Creates a new git tag when a PR is merged, or on manual dispatch
2+
#
3+
# PR trigger flow:
4+
# - Triggered whenever a PR is merged, if that PR made code changes
5+
# - If version wasn't bumped in PR, increment patch version and update package.json
6+
# - Otherwise (if the PR did bump version) we use the new version from package.json
7+
# - Creates and pushes a git tag for the new version
8+
# - That git tag then triggers Docker publishing and AWS deployment in other CI
9+
# - Add tags to issues from newly released features/fixes (if applicable)
10+
# - Finally, shows summary of actions taken and new tag published
11+
#
12+
# Manual dispatch flow:
13+
# - If a version is provided, sets package.json to that version
14+
# - If no version is provided, increments patch version automatically
15+
# - Creates and pushes a git tag for the new version
16+
name: 🔖 Auto Version & Tag
17+
18+
on:
19+
workflow_dispatch:
20+
inputs:
21+
version:
22+
description: 'Version to release (e.g. 2.1.0). Leave blank to auto-increment patch.'
23+
required: false
24+
type: string
25+
pull_request_target:
26+
types: [closed]
27+
branches: [master]
28+
29+
concurrency:
30+
group: auto-version-and-tag
31+
cancel-in-progress: false
32+
33+
permissions:
34+
contents: write
35+
pull-requests: read
36+
issues: write
37+
38+
env:
39+
IS_MANUAL: ${{ github.event_name == 'workflow_dispatch' }}
40+
41+
jobs:
42+
version-and-tag:
43+
if: >-
44+
github.event_name == 'workflow_dispatch'
45+
|| github.event.pull_request.merged == true
46+
runs-on: ubuntu-latest
47+
steps:
48+
- name: Validate manual version input 🔢
49+
if: env.IS_MANUAL == 'true' && inputs.version != ''
50+
env:
51+
INPUT_VERSION: ${{ inputs.version }}
52+
run: |
53+
if ! echo "$INPUT_VERSION" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then
54+
echo "::error::Invalid version '${INPUT_VERSION}'. Must be semver (e.g. 2.1.0)."
55+
exit 1
56+
fi
57+
58+
- name: Check PR for code changes and version bump 📂
59+
id: check_pr
60+
if: env.IS_MANUAL != 'true'
61+
uses: actions/github-script@v9
62+
with:
63+
script: |
64+
const { owner, repo } = context.repo;
65+
const pull_number = context.payload.pull_request.number;
66+
67+
const files = await github.paginate(
68+
github.rest.pulls.listFiles, { owner, repo, pull_number }
69+
);
70+
const codePatterns = [
71+
/^src\//, /^api\//, /^public\//, /^Dockerfile$/, /^[^/]+\.(js|mjs)$/,
72+
];
73+
const codeChanged = files.some(f =>
74+
codePatterns.some(p => p.test(f.filename))
75+
);
76+
const pkgChanged = files.some(f => f.filename === 'package.json');
77+
78+
if (!codeChanged && !pkgChanged) {
79+
core.info('No code or package.json changes, skipping');
80+
core.setOutput('needs_bump', 'false');
81+
core.setOutput('needs_tag', 'false');
82+
return;
83+
}
84+
85+
let versionBumped = false;
86+
if (pkgChanged) {
87+
const mergeSha = context.payload.pull_request.merge_commit_sha;
88+
const { data: mergeCommit } = await github.rest.git.getCommit({
89+
owner, repo, commit_sha: mergeSha,
90+
});
91+
const parentSha = mergeCommit.parents[0].sha;
92+
const getVersion = async (ref) => {
93+
const { data } = await github.rest.repos.getContent({
94+
owner, repo, path: 'package.json', ref,
95+
});
96+
return JSON.parse(Buffer.from(data.content, 'base64').toString()).version;
97+
};
98+
const [prevVersion, mergeVersion] = await Promise.all([
99+
getVersion(parentSha), getVersion(mergeSha),
100+
]);
101+
versionBumped = prevVersion !== mergeVersion;
102+
core.info(`Version: ${prevVersion} → ${mergeVersion}`);
103+
}
104+
105+
const needsBump = codeChanged && !versionBumped;
106+
const needsTag = codeChanged || versionBumped;
107+
core.info(`Needs bump: ${needsBump}, Needs tag: ${needsTag}`);
108+
core.setOutput('needs_bump', needsBump.toString());
109+
core.setOutput('needs_tag', needsTag.toString());
110+
111+
- name: Checkout repository 🛎️
112+
if: env.IS_MANUAL == 'true' || steps.check_pr.outputs.needs_tag == 'true'
113+
uses: actions/checkout@v6
114+
with:
115+
token: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
116+
117+
- name: Configure git identity 👤
118+
if: env.IS_MANUAL == 'true' || steps.check_pr.outputs.needs_tag == 'true'
119+
run: |
120+
git config user.name "Liss-Bot"
121+
git config user.email "liss-bot@d0h.co"
122+
123+
- name: Extract referenced issues 🔍
124+
id: issues
125+
if: env.IS_MANUAL != 'true' && steps.check_pr.outputs.needs_tag == 'true'
126+
uses: actions/github-script@v9
127+
with:
128+
script: |
129+
const body = context.payload.pull_request.body || '';
130+
const prNumber = String(context.payload.pull_request.number);
131+
const matches = body.match(/#(\d+)(?![a-fA-F0-9])/g);
132+
if (!matches) {
133+
core.info('No issue references found in PR body');
134+
core.setOutput('numbers', '');
135+
return;
136+
}
137+
const unique = [...new Set(matches.map(m => m.replace('#', '')))]
138+
.filter(n => n !== prNumber && parseInt(n, 10) > 0);
139+
if (unique.length === 0) {
140+
core.info('No issue references after filtering');
141+
core.setOutput('numbers', '');
142+
return;
143+
}
144+
core.info(`Found issue references: ${unique.join(', ')}`);
145+
core.setOutput('numbers', unique.join(','));
146+
147+
- name: Bump version ⬆️
148+
if: >-
149+
env.IS_MANUAL == 'true'
150+
|| steps.check_pr.outputs.needs_bump == 'true'
151+
env:
152+
INPUT_VERSION: ${{ inputs.version }}
153+
run: |
154+
if [ "$IS_MANUAL" = "true" ] && [ -n "$INPUT_VERSION" ]; then
155+
npm version "$INPUT_VERSION" --no-git-tag-version --allow-same-version
156+
else
157+
npm version patch --no-git-tag-version
158+
fi
159+
git add package.json
160+
git commit -m "🔖 Bump version to $(node -p "require('./package.json').version")"
161+
git push
162+
163+
- name: Create and push tag 🏷️
164+
id: tag
165+
if: env.IS_MANUAL == 'true' || steps.check_pr.outputs.needs_tag == 'true'
166+
env:
167+
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
168+
PR_TITLE: ${{ github.event.pull_request.title || '' }}
169+
PR_AUTHOR: ${{ github.event.pull_request.user.login || github.actor }}
170+
MERGE_SHA: ${{ github.event.pull_request.merge_commit_sha || github.sha }}
171+
ISSUES: ${{ steps.issues.outputs.numbers }}
172+
run: |
173+
VERSION=$(node -p "require('./package.json').version")
174+
git fetch --tags --force
175+
if git rev-parse "refs/tags/$VERSION" >/dev/null 2>&1; then
176+
echo "Tag $VERSION already exists, skipping"
177+
exit 0
178+
fi
179+
180+
{
181+
printf 'Web-Check v%s 🚀\n\n' "$VERSION"
182+
if [ -n "$PR_NUMBER" ]; then
183+
printf 'PR: #%s - %s\n' "$PR_NUMBER" "$PR_TITLE"
184+
else
185+
printf 'Manual release by @%s\n' "$PR_AUTHOR"
186+
fi
187+
if [ -n "$ISSUES" ]; then
188+
printf 'Resolves: %s\n' "$(echo "$ISSUES" | sed 's/,/, #/g; s/^/#/')"
189+
fi
190+
printf 'Author: @%s\n' "$PR_AUTHOR"
191+
printf 'Commit: %s\n' "$MERGE_SHA"
192+
} > tag-message.txt
193+
194+
git tag -a "$VERSION" -F tag-message.txt
195+
git push origin "$VERSION"
196+
197+
- name: Label referenced issues 🛩️
198+
id: label
199+
if: >-
200+
env.IS_MANUAL != 'true'
201+
&& steps.check_pr.outputs.needs_tag == 'true'
202+
&& steps.issues.outputs.numbers != ''
203+
continue-on-error: true
204+
uses: actions/github-script@v9
205+
env:
206+
ISSUES: ${{ steps.issues.outputs.numbers }}
207+
with:
208+
github-token: ${{ secrets.BOT_TOKEN || secrets.GITHUB_TOKEN }}
209+
script: |
210+
const { owner, repo } = context.repo;
211+
const { version } = JSON.parse(require('fs').readFileSync('package.json', 'utf8'));
212+
const labelName = `🛩️ Released ${version}`;
213+
const issues = process.env.ISSUES.split(',').filter(Boolean);
214+
215+
try {
216+
await github.rest.issues.createLabel({
217+
owner, repo,
218+
name: labelName,
219+
color: 'EDEDED',
220+
description: `Included in release v${version}`,
221+
});
222+
core.info(`Created label: ${labelName}`);
223+
} catch (e) {
224+
if (e.status === 422) {
225+
core.info(`Label already exists: ${labelName}`);
226+
} else {
227+
core.warning(`Failed to create label: ${e.message}`);
228+
}
229+
}
230+
231+
const prNumber = context.payload.pull_request.number;
232+
const prAuthor = context.payload.pull_request.user?.login;
233+
const creditAuthor = prAuthor && prAuthor.toLowerCase() !== 'lissy93';
234+
const marker = `released-${version}`;
235+
for (const num of issues) {
236+
const issue_number = parseInt(num, 10);
237+
try {
238+
const [{ data: issue }, comments] = await Promise.all([
239+
github.rest.issues.get({ owner, repo, issue_number }),
240+
github.rest.issues.listComments({
241+
owner, repo, issue_number, per_page: 100,
242+
}),
243+
]);
244+
const alreadyCommented = comments.data.some(
245+
c => c.body?.includes(marker)
246+
);
247+
if (!alreadyCommented) {
248+
const author = issue.user?.login;
249+
const greeting = author ? `Hey @${author},` : 'Hey,';
250+
const sixMonthsAgo = new Date();
251+
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
252+
const isOld = new Date(issue.created_at) < sixMonthsAgo;
253+
const byLine = creditAuthor ? ` by @${prAuthor}` : '';
254+
const parts = [
255+
greeting,
256+
`this has now been implemented${byLine} in #${prNumber},`,
257+
`and will be released shortly in ${version} 😇`,
258+
];
259+
if (isOld) parts.push(`\n\nWe're sorry this one took so long 😔`);
260+
parts.push(`<!-- ${marker} -->`);
261+
const body = parts.join(' ');
262+
await github.rest.issues.createComment({
263+
owner, repo, issue_number, body,
264+
});
265+
}
266+
await github.rest.issues.addLabels({
267+
owner, repo, issue_number, labels: [labelName, '✅ Fixed'],
268+
});
269+
core.info(alreadyCommented
270+
? `Already commented on #${num}, labels applied`
271+
: `Commented and labeled #${num}`);
272+
} catch (e) {
273+
core.warning(`Failed to process #${num}: ${e.message}`);
274+
}
275+
}
276+
277+
- name: Job summary 📋
278+
if: always()
279+
env:
280+
PR_NUMBER: ${{ github.event.pull_request.number || '' }}
281+
PR_TITLE: ${{ github.event.pull_request.title || '' }}
282+
REPO_URL: ${{ github.server_url }}/${{ github.repository }}
283+
NEEDS_BUMP: ${{ steps.check_pr.outputs.needs_bump }}
284+
NEEDS_TAG: ${{ steps.check_pr.outputs.needs_tag }}
285+
ISSUES: ${{ steps.issues.outputs.numbers }}
286+
TAG_OUTCOME: ${{ steps.tag.outcome }}
287+
LABEL_OUTCOME: ${{ steps.label.outcome }}
288+
run: |
289+
VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "unknown")
290+
291+
{
292+
echo "## 🔖 Auto Version & Tag"
293+
echo ""
294+
echo "| Step | Result |"
295+
echo "|------|--------|"
296+
297+
if [ "$IS_MANUAL" = "true" ]; then
298+
echo "| Trigger | Manual dispatch |"
299+
elif [ -n "$PR_NUMBER" ]; then
300+
echo "| PR | [#${PR_NUMBER}](${REPO_URL}/pull/${PR_NUMBER}) — ${PR_TITLE} |"
301+
fi
302+
303+
if [ "$IS_MANUAL" = "true" ] || [ "$NEEDS_BUMP" = "true" ]; then
304+
echo "| Version bump | ✅ \`${VERSION}\` |"
305+
else
306+
echo "| Version bump | ⏭️ Skipped |"
307+
fi
308+
309+
if [ "$TAG_OUTCOME" = "success" ]; then
310+
echo "| Tag | ✅ [\`${VERSION}\`](${REPO_URL}/releases/tag/${VERSION}) |"
311+
elif [ "$IS_MANUAL" = "true" ] || [ "$NEEDS_TAG" = "true" ]; then
312+
echo "| Tag | ❌ Failed |"
313+
else
314+
echo "| Tag | ⏭️ Skipped |"
315+
fi
316+
317+
if [ -n "$ISSUES" ]; then
318+
ISSUE_LINKS=$(echo "$ISSUES" | tr ',' '\n' | sed "s|.*|[#&](${REPO_URL}/issues/&)|" | paste -sd ' ' -)
319+
if [ "$LABEL_OUTCOME" = "success" ]; then
320+
echo "| Issues labeled | ✅ ${ISSUE_LINKS} |"
321+
else
322+
echo "| Issues labeled | ⚠️ ${ISSUE_LINKS} |"
323+
fi
324+
fi
325+
} >> "$GITHUB_STEP_SUMMARY"

0 commit comments

Comments
 (0)