Skip to content

Commit b77c958

Browse files
author
“Kirti
committed
github actions security and automation flows
1 parent 2b00a8a commit b77c958

5 files changed

Lines changed: 578 additions & 47 deletions

File tree

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
name: Security Audit
2+
3+
on:
4+
push:
5+
branches: [ master, main ]
6+
pull_request:
7+
branches: [ master, main ]
8+
schedule:
9+
- cron: '0 9 * * 1' # Every Monday at 9am UTC
10+
workflow_dispatch:
11+
12+
jobs:
13+
audit:
14+
runs-on: ubuntu-latest
15+
permissions:
16+
contents: read
17+
issues: write
18+
19+
steps:
20+
- name: Checkout code
21+
uses: actions/checkout@v4
22+
23+
- name: Setup Node.js
24+
uses: actions/setup-node@v4
25+
with:
26+
node-version: '22'
27+
cache: 'npm'
28+
29+
- name: Install dependencies
30+
run: npm ci
31+
32+
- name: Run security audit
33+
id: audit
34+
run: |
35+
npm audit --audit-level=critical --json > audit-results.json || true
36+
CRITICAL=$(cat audit-results.json | node -e "
37+
const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
38+
console.log(d.metadata?.vulnerabilities?.critical || 0)
39+
")
40+
HIGH=$(cat audit-results.json | node -e "
41+
const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));
42+
console.log(d.metadata?.vulnerabilities?.high || 0)
43+
")
44+
echo "critical=$CRITICAL" >> $GITHUB_OUTPUT
45+
echo "high=$HIGH" >> $GITHUB_OUTPUT
46+
echo "Critical: $CRITICAL, High: $HIGH"
47+
48+
- name: Upload audit results
49+
uses: actions/upload-artifact@v4
50+
with:
51+
name: audit-results
52+
path: audit-results.json
53+
retention-days: 30
54+
55+
- name: Fail on critical vulnerabilities
56+
if: steps.audit.outputs.critical > 0
57+
run: |
58+
echo "❌ Found ${{ steps.audit.outputs.critical }} critical vulnerabilities!"
59+
echo "Run 'npm audit fix' to remediate"
60+
exit 1
61+
62+
- name: Auto-create issue on critical CVEs
63+
if: failure() && github.event_name == 'schedule'
64+
uses: actions/github-script@v7
65+
with:
66+
script: |
67+
const critical = '${{ steps.audit.outputs.critical }}';
68+
const high = '${{ steps.audit.outputs.high }}';
69+
const date = new Date().toISOString().split('T')[0];
70+
71+
// Check if issue already exists this week
72+
const { data: issues } = await github.rest.issues.listForRepo({
73+
owner: context.repo.owner,
74+
repo: context.repo.repo,
75+
state: 'open',
76+
labels: 'security'
77+
});
78+
79+
const existing = issues.find(i => i.title.includes('Security Audit'));
80+
if (existing) {
81+
await github.rest.issues.update({
82+
owner: context.repo.owner,
83+
repo: context.repo.repo,
84+
issue_number: existing.number,
85+
body: `## 🔴 Security Audit — ${date}\n\n**Critical:** ${critical}\n**High:** ${high}\n\n### Remediation\n\`\`\`bash\nnpm audit fix\nnpm audit fix --force # for breaking changes\n\`\`\`\n\n[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`
86+
});
87+
} else {
88+
await github.rest.issues.create({
89+
owner: context.repo.owner,
90+
repo: context.repo.repo,
91+
title: `🔴 Security Audit: ${critical} critical CVEs found — ${date}`,
92+
body: `## Security Audit — ${date}\n\n**Critical:** ${critical}\n**High:** ${high}\n\n### Remediation\n\`\`\`bash\nnpm audit fix\nnpm audit fix --force # for breaking changes\n\`\`\`\n\n[View workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})`,
93+
labels: ['security', 'automated']
94+
});
95+
}
96+
97+
- name: Summary
98+
if: always()
99+
run: |
100+
echo "## Security Audit Results" >> $GITHUB_STEP_SUMMARY
101+
echo "| Severity | Count |" >> $GITHUB_STEP_SUMMARY
102+
echo "|----------|-------|" >> $GITHUB_STEP_SUMMARY
103+
echo "| Critical | ${{ steps.audit.outputs.critical }} |" >> $GITHUB_STEP_SUMMARY
104+
echo "| High | ${{ steps.audit.outputs.high }} |" >> $GITHUB_STEP_SUMMARY
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
name: Release Automation
2+
3+
on:
4+
push:
5+
branches: [ main, master ]
6+
paths-ignore:
7+
- '**.md'
8+
- '.github/workflows/**'
9+
workflow_dispatch:
10+
inputs:
11+
release_type:
12+
description: 'Release type (patch, minor, major)'
13+
required: true
14+
default: 'patch'
15+
type: choice
16+
options: [patch, minor, major]
17+
18+
permissions:
19+
contents: write
20+
pull-requests: write
21+
22+
jobs:
23+
release:
24+
runs-on: ubuntu-latest
25+
# Only run if commit message signals a release
26+
if: |
27+
contains(github.event.head_commit.message, 'feat:') ||
28+
contains(github.event.head_commit.message, 'fix:') ||
29+
contains(github.event.head_commit.message, 'release:') ||
30+
github.event_name == 'workflow_dispatch'
31+
32+
steps:
33+
- name: Checkout code
34+
uses: actions/checkout@v4
35+
with:
36+
fetch-depth: 0 # Full history for changelog generation
37+
token: ${{ secrets.GITHUB_TOKEN }}
38+
39+
- name: Setup Node.js
40+
uses: actions/setup-node@v4
41+
with:
42+
node-version: '22'
43+
cache: 'npm'
44+
45+
- name: Configure git
46+
run: |
47+
git config user.name "github-actions[bot]"
48+
git config user.email "github-actions[bot]@users.noreply.github.com"
49+
50+
- name: Install dependencies
51+
run: npm ci
52+
53+
- name: Run tests before release
54+
run: npm test -- --passWithNoTests --watchAll=false
55+
56+
- name: Build
57+
run: npm run build
58+
59+
- name: Determine release type
60+
id: release-type
61+
run: |
62+
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
63+
echo "type=${{ github.event.inputs.release_type }}" >> $GITHUB_OUTPUT
64+
else
65+
# Auto-detect from commit message
66+
MSG="${{ github.event.head_commit.message }}"
67+
if echo "$MSG" | grep -q "BREAKING CHANGE\|major:"; then
68+
echo "type=major" >> $GITHUB_OUTPUT
69+
elif echo "$MSG" | grep -q "feat:"; then
70+
echo "type=minor" >> $GITHUB_OUTPUT
71+
else
72+
echo "type=patch" >> $GITHUB_OUTPUT
73+
fi
74+
fi
75+
76+
- name: Bump version
77+
id: version
78+
run: |
79+
npm version ${{ steps.release-type.outputs.type }} --no-git-tag-version
80+
NEW_VERSION=$(node -p "require('./package.json').version")
81+
echo "version=$NEW_VERSION" >> $GITHUB_OUTPUT
82+
echo "New version: $NEW_VERSION"
83+
84+
- name: Generate changelog
85+
id: changelog
86+
run: |
87+
# Get commits since last tag
88+
LAST_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
89+
if [ -z "$LAST_TAG" ]; then
90+
COMMITS=$(git log --pretty=format:"- %s (%h)" -20)
91+
else
92+
COMMITS=$(git log ${LAST_TAG}..HEAD --pretty=format:"- %s (%h)")
93+
fi
94+
95+
# Categorize commits
96+
FEATURES=$(echo "$COMMITS" | grep "^- feat:" || echo "")
97+
FIXES=$(echo "$COMMITS" | grep "^- fix:" || echo "")
98+
OTHER=$(echo "$COMMITS" | grep -v "^- feat:\|^- fix:" || echo "")
99+
100+
CHANGELOG="## What's Changed in v${{ steps.version.outputs.version }}"
101+
102+
if [ -n "$FEATURES" ]; then
103+
CHANGELOG="$CHANGELOG\n\n### ✨ New Features\n$FEATURES"
104+
fi
105+
if [ -n "$FIXES" ]; then
106+
CHANGELOG="$CHANGELOG\n\n### 🐛 Bug Fixes\n$FIXES"
107+
fi
108+
if [ -n "$OTHER" ]; then
109+
CHANGELOG="$CHANGELOG\n\n### 🔧 Other Changes\n$OTHER"
110+
fi
111+
112+
echo "changelog<<EOF" >> $GITHUB_OUTPUT
113+
echo -e "$CHANGELOG" >> $GITHUB_OUTPUT
114+
echo "EOF" >> $GITHUB_OUTPUT
115+
116+
- name: Commit version bump
117+
run: |
118+
git add package.json package-lock.json
119+
git commit -m "chore: release v${{ steps.version.outputs.version }} [skip ci]"
120+
git tag "v${{ steps.version.outputs.version }}"
121+
git push origin HEAD --tags
122+
123+
- name: Create GitHub Release
124+
uses: actions/github-script@v7
125+
with:
126+
script: |
127+
await github.rest.repos.createRelease({
128+
owner: context.repo.owner,
129+
repo: context.repo.repo,
130+
tag_name: `v${{ steps.version.outputs.version }}`,
131+
name: `v${{ steps.version.outputs.version }}`,
132+
body: `${{ steps.changelog.outputs.changelog }}`,
133+
draft: false,
134+
prerelease: false
135+
});
136+
137+
- name: Summary
138+
run: |
139+
echo "## 🚀 Released v${{ steps.version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
140+
echo "Type: ${{ steps.release-type.outputs.type }}" >> $GITHUB_STEP_SUMMARY
141+
echo "" >> $GITHUB_STEP_SUMMARY
142+
echo "${{ steps.changelog.outputs.changelog }}" >> $GITHUB_STEP_SUMMARY
File renamed without changes.

src/App.css

Lines changed: 101 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,110 @@
1-
.App {
2-
text-align: center;
3-
}
1+
* { margin: 0; padding: 0; box-sizing: border-box; }
42

5-
.App-logo {
6-
height: 40vmin;
7-
pointer-events: none;
8-
}
3+
@import url('https://fonts.googleapis.com/css2?family=DM+Mono:wght@300;400;500&family=Syne:wght@400;600;700;800&display=swap');
94

10-
@media (prefers-reduced-motion: no-preference) {
11-
.App-logo {
12-
animation: App-logo-spin infinite 20s linear;
13-
}
5+
:root {
6+
--bg: #070a0f;
7+
--surface: #0d1117;
8+
--surface2: #161b22;
9+
--border: #21262d;
10+
--accent: #00d4aa;
11+
--accent2: #7c3aed;
12+
--accent3: #f59e0b;
13+
--text: #e6edf3;
14+
--text2: #8b949e;
15+
--green: #3fb950;
16+
--red: #f85149;
17+
--blue: #58a6ff;
1418
}
1519

16-
.App-header {
17-
background-color: #282c34;
20+
body {
21+
background: var(--bg);
22+
color: var(--text);
23+
font-family: 'Syne', sans-serif;
1824
min-height: 100vh;
19-
display: flex;
20-
flex-direction: column;
21-
align-items: center;
22-
justify-content: center;
23-
font-size: calc(10px + 2vmin);
24-
color: white;
25+
overflow-x: hidden;
2526
}
2627

27-
.App-link {
28-
color: #61dafb;
29-
}
28+
.mono { font-family: 'DM Mono', monospace; }
3029

31-
@keyframes App-logo-spin {
32-
from {
33-
transform: rotate(0deg);
34-
}
35-
to {
36-
transform: rotate(360deg);
37-
}
30+
/* Grid background */
31+
body::before {
32+
content: '';
33+
position: fixed;
34+
inset: 0;
35+
background-image:
36+
linear-gradient(rgba(0,212,170,0.03) 1px, transparent 1px),
37+
linear-gradient(90deg, rgba(0,212,170,0.03) 1px, transparent 1px);
38+
background-size: 40px 40px;
39+
pointer-events: none;
40+
z-index: 0;
3841
}
42+
43+
.app { position: relative; z-index: 1; max-width: 1100px; margin: 0 auto; padding: 40px 24px 80px; }
44+
45+
/* Hero */
46+
.hero { text-align: center; padding: 60px 0 48px; }
47+
.hero-eyebrow { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--accent); letter-spacing: 0.2em; text-transform: uppercase; margin-bottom: 20px; display: flex; align-items: center; justify-content: center; gap: 8px; }
48+
.hero-eyebrow::before, .hero-eyebrow::after { content: ''; width: 32px; height: 1px; background: var(--accent); opacity: 0.4; }
49+
.hero h1 { font-size: clamp(2rem, 5vw, 3.5rem); font-weight: 800; line-height: 1.1; margin-bottom: 16px; }
50+
.hero h1 span { color: var(--accent); }
51+
.hero p { font-family: 'DM Mono', monospace; font-size: 14px; color: var(--text2); max-width: 560px; margin: 0 auto 32px; line-height: 1.7; }
52+
.badge-row { display: flex; gap: 8px; justify-content: center; flex-wrap: wrap; margin-bottom: 12px; }
53+
.badge { font-family: 'DM Mono', monospace; font-size: 11px; padding: 4px 10px; border-radius: 4px; border: 1px solid; }
54+
.badge-green { color: var(--green); border-color: rgba(63,185,80,0.3); background: rgba(63,185,80,0.08); }
55+
.badge-blue { color: var(--blue); border-color: rgba(88,166,255,0.3); background: rgba(88,166,255,0.08); }
56+
.badge-amber { color: var(--accent3); border-color: rgba(245,158,11,0.3); background: rgba(245,158,11,0.08); }
57+
.badge-teal { color: var(--accent); border-color: rgba(0,212,170,0.3); background: rgba(0,212,170,0.08); }
58+
.badge-purple { color: #a78bfa; border-color: rgba(124,58,237,0.3); background: rgba(124,58,237,0.08); }
59+
60+
/* Section */
61+
.section { margin-bottom: 48px; }
62+
.section-label { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text2); letter-spacing: 0.15em; text-transform: uppercase; margin-bottom: 16px; display: flex; align-items: center; gap: 12px; }
63+
.section-label::after { content: ''; flex: 1; height: 1px; background: var(--border); }
64+
65+
/* Workflow cards */
66+
.workflow-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); gap: 12px; }
67+
.wf-card { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 18px 20px; transition: border-color 0.2s, transform 0.2s; cursor: default; }
68+
.wf-card:hover { border-color: var(--accent); transform: translateY(-2px); }
69+
.wf-card-head { display: flex; align-items: flex-start; justify-content: space-between; margin-bottom: 10px; gap: 8px; }
70+
.wf-name { font-size: 13px; font-weight: 700; color: var(--text); }
71+
.wf-file { font-family: 'DM Mono', monospace; font-size: 10px; color: var(--text2); margin-top: 2px; }
72+
.status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--green); box-shadow: 0 0 6px var(--green); flex-shrink: 0; margin-top: 4px; animation: pulse 2s infinite; }
73+
@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.4; } }
74+
.wf-desc { font-size: 12px; color: var(--text2); line-height: 1.6; margin-bottom: 12px; }
75+
.wf-tags { display: flex; gap: 6px; flex-wrap: wrap; }
76+
.wf-tag { font-family: 'DM Mono', monospace; font-size: 10px; color: var(--text2); background: var(--surface2); border: 1px solid var(--border); border-radius: 3px; padding: 2px 7px; }
77+
78+
/* Pipeline viz */
79+
.pipeline { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 24px; margin-bottom: 12px; }
80+
.pipeline-title { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text2); margin-bottom: 16px; }
81+
.pipeline-flow { display: flex; align-items: center; gap: 0; flex-wrap: wrap; }
82+
.pipeline-step { display: flex; align-items: center; gap: 0; }
83+
.step-box { background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; padding: 10px 14px; text-align: center; min-width: 90px; }
84+
.step-icon { font-size: 16px; margin-bottom: 4px; }
85+
.step-name { font-family: 'DM Mono', monospace; font-size: 10px; color: var(--text); }
86+
.step-time { font-family: 'DM Mono', monospace; font-size: 9px; color: var(--accent); margin-top: 2px; }
87+
.arrow { font-size: 12px; color: var(--border); padding: 0 6px; }
88+
89+
/* Metrics */
90+
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 12px; margin-bottom: 12px; }
91+
.metric { background: var(--surface); border: 1px solid var(--border); border-radius: 8px; padding: 16px 18px; }
92+
.metric-val { font-size: 28px; font-weight: 800; color: var(--text); line-height: 1; margin-bottom: 4px; }
93+
.metric-val span { color: var(--accent); }
94+
.metric-label { font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text2); }
95+
96+
/* New workflows */
97+
.new-wf { background: var(--surface); border: 1px solid rgba(0,212,170,0.3); border-radius: 8px; padding: 20px; margin-bottom: 10px; }
98+
.new-wf-head { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
99+
.new-badge { font-family: 'DM Mono', monospace; font-size: 10px; background: rgba(0,212,170,0.15); color: var(--accent); border: 1px solid rgba(0,212,170,0.3); border-radius: 3px; padding: 2px 7px; }
100+
.new-wf-title { font-size: 14px; font-weight: 700; }
101+
.new-wf-desc { font-size: 12px; color: var(--text2); line-height: 1.6; }
102+
.code-block { background: var(--surface2); border: 1px solid var(--border); border-radius: 6px; padding: 14px 16px; margin-top: 12px; font-family: 'DM Mono', monospace; font-size: 11px; color: var(--text2); line-height: 1.7; overflow-x: auto; white-space: pre; }
103+
.code-block .kw { color: #ff7b72; }
104+
.code-block .str { color: #a5d6ff; }
105+
.code-block .cm { color: #8b949e; }
106+
.code-block .val { color: var(--accent); }
107+
108+
/* Footer */
109+
.footer { text-align: center; padding-top: 40px; border-top: 1px solid var(--border); font-family: 'DM Mono', monospace; font-size: 12px; color: var(--text2); line-height: 2; }
110+
.footer a { color: var(--accent); text-decoration: none; }

0 commit comments

Comments
 (0)