Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
171 changes: 171 additions & 0 deletions .github/workflows/pr-security-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
name: PR Security Check

on:
pull_request:
types: [opened, synchronize, reopened]
branches: [main]
paths:
- 'src/**'
- 'public/**'
- 'package.json'
- 'package-lock.json'
- 'scripts/**'
- '.github/workflows/**'
# Also run on pushes to feature branches
push:
branches-ignore:
- main
- develop
- gh-pages
- deploy
paths:
- 'src/**'
- 'public/**'
- 'package.json'
- 'package-lock.json'
- 'scripts/**'
- '.github/workflows/**'

permissions:
contents: read
pull-requests: write

jobs:
security-check:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v5

- name: Setup Node.js
uses: actions/setup-node@v5
with:
node-version: '20'
cache: 'npm'

- name: Get PR information
id: pr_info
uses: actions/github-script@v8
with:
script: |
let prNumber = null;

if (context.payload.pull_request) {
// Direct PR event
prNumber = context.payload.pull_request.number;
} else if (context.eventName === 'push') {
// Push event - find associated PR
const branchName = context.ref.replace('refs/heads/', '');
const { data: prs } = await github.rest.pulls.list({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
head: `${context.repo.owner}:${branchName}`
});

if (prs.length > 0) {
prNumber = prs[0].number;
}
}

console.log(`PR Number: ${prNumber}`);
core.setOutput('pr_number', prNumber || '');

return prNumber;

- name: Install dependencies
run: npm ci --legacy-peer-deps
continue-on-error: false

- name: Run security checks
id: security_check
continue-on-error: true
run: |
echo "🔒 Running comprehensive security checks..."

# Run the security check script
node scripts/run-security-checks.js

# Capture exit code
exit_code=$?
echo "security_exit_code=$exit_code" >> $GITHUB_OUTPUT

# Always continue to format the comment even if checks fail
exit 0

- name: Format security comment
id: format_comment
if: always()
run: |
echo "📝 Formatting security check results..."

# Check if results file exists
if [ -f "security-check-results.json" ]; then
node scripts/format-security-comment.js
echo "comment_available=true" >> $GITHUB_OUTPUT
else
echo "⚠️ Security check results not found"
echo "comment_available=false" >> $GITHUB_OUTPUT
fi

- name: Update PR comment
if: always() && steps.pr_info.outputs.pr_number != '' && steps.format_comment.outputs.comment_available == 'true'
continue-on-error: true
run: |
python3 scripts/manage-security-comment.py \
--token "${{ secrets.GITHUB_TOKEN }}" \
Comment on lines +115 to +117
Copy link

Copilot AI Oct 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GitHub token is passed as a command line argument, which could potentially expose it in process lists or logs. Consider using environment variables instead: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

Suggested change
run: |
python3 scripts/manage-security-comment.py \
--token "${{ secrets.GITHUB_TOKEN }}" \
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
python3 scripts/manage-security-comment.py \

Copilot uses AI. Check for mistakes.
--repo "${{ github.repository }}" \
--pr "${{ steps.pr_info.outputs.pr_number }}" \
--comment-file "security-comment.md"

- name: Set status check
if: always() && steps.pr_info.outputs.pr_number != ''
uses: actions/github-script@v8
with:
script: |
const exitCode = '${{ steps.security_check.outputs.security_exit_code }}';
const prNumber = '${{ steps.pr_info.outputs.pr_number }}';

// Read results to get more details
const fs = require('fs');
let summary = 'Security checks completed';
let conclusion = 'success';

try {
if (fs.existsSync('security-check-results.json')) {
const results = JSON.parse(fs.readFileSync('security-check-results.json', 'utf8'));
const s = results.summary;

if (s.failed > 0) {
conclusion = 'failure';
summary = `Security issues found: ${s.failed} failed, ${s.warned} warnings`;
} else if (s.warned > 0) {
conclusion = 'neutral';
summary = `Security warnings: ${s.warned} warnings, ${s.passed} passed`;
} else {
conclusion = 'success';
summary = `All security checks passed: ${s.passed} checks`;
}
}
} catch (e) {
console.error('Error reading results:', e);
}

console.log(`Security check conclusion: ${conclusion}`);
console.log(`Summary: ${summary}`);

// Don't fail the workflow for warnings
if (conclusion === 'failure') {
core.setFailed(summary);
}

- name: Upload security results as artifact
if: always()
uses: actions/upload-artifact@v4
with:
name: security-check-results
path: |
security-check-results.json
security-comment.md
retention-days: 30
7 changes: 7 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -112,3 +112,10 @@ test-pr-feedback-improvements.md
# Deployment structure (generated by CI/CD)
sgex/public/404-complex-backup.html
scripts/__pycache__/

# Security check results (generated by CI/CD)
security-check-results.json
security-comment.md
eslint-results.json
audit_results.txt
audit_results.json
1 change: 1 addition & 0 deletions DEPLOYMENT.md
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ The following additional workflows provide build quality, security, and feedback
### Code Quality & Compliance Workflows
- **Framework Compliance Check**: [`.github/workflows/framework-compliance.yml`](.github/workflows/framework-compliance.yml) - Validates page framework standards and TypeScript compliance
- **Dependency Security Check**: [`.github/workflows/dependency-security.yml`](.github/workflows/dependency-security.yml) - Scans for security vulnerabilities in dependencies
- **PR Security Check**: [`.github/workflows/pr-security-check.yml`](.github/workflows/pr-security-check.yml) - Comprehensive security checks on every PR build (npm audit, outdated dependencies, ESLint security, security headers, license compliance, secret scanning, framework compliance)

### Workflow Configuration Details
All workflows include:
Expand Down
130 changes: 1 addition & 129 deletions MERGE_CONFLICT_ANALYSIS.md
Original file line number Diff line number Diff line change
@@ -1,132 +1,3 @@
# Merge Conflict Analysis - Fix 404 Errors for Assets PR

**Generated:** 2025-10-11
**Branch:** copilot/fix-404-errors-for-assets
**Target:** main

---

## Conflict Summary

**Conflicting File:** `src/services/helpContentService.js`

**Conflict Type:** Content modification conflict
**Severity:** Low - Simple path reference conflict
**Resolution Complexity:** Simple string replacement

---

## Conflict Details

### What Changed in This PR Branch

Changed all badge icon paths from **absolute paths** to **relative paths** to fix 404 errors in feature branch deployments:

```javascript
// BEFORE (in this PR branch at commit 66f083c)
badge: 'cat-paw-info-icon.svg' // Line 11
badge: 'cat-paw-workflow-icon.svg' // Line 59
badge: 'cat-paw-lock-icon.svg' // Line 93
badge: 'cat-paw-bug-icon.svg' // Line ~150+
// ... and 13 more badge references
```

### What Changed in Main Branch

Main branch retained the **absolute paths** with `/sgex/` prefix:

```javascript
// CURRENT (in main branch at commit 09cfe1f)
badge: '/sgex/cat-paw-info-icon.svg' // Line 11
badge: '/sgex/cat-paw-workflow-icon.svg' // Line 59
badge: '/sgex/cat-paw-lock-icon.svg' // Line 93
badge: '/sgex/cat-paw-bug-icon.svg' // Line ~150+
// ... and 13 more badge references
```

### Why This Conflict Exists

Both branches modified the same badge path lines:
- **This PR branch:** Changed absolute paths (`/sgex/cat-paw-*.svg`) to relative paths (`cat-paw-*.svg`)
- **Main branch:** Added new badge references or modified help content while keeping absolute paths

Git cannot automatically merge because it doesn't know which version to keep.

---

## Resolution Options

### Option 1: Accept This PR's Changes (Recommended) ✅

**What it does:** Keep all relative badge paths from this PR branch
**Why recommended:** Fixes the 404 errors in feature branch deployments

**Benefits:**
- ✅ Fixes 404 errors in all deployment scenarios (local, main, feature branches)
- ✅ Simpler and more portable code
- ✅ No hardcoded path prefixes
- ✅ Browser resolves paths relative to current page URL
- ✅ Already tested and working in this PR

**How to resolve:**
```bash
# Keep all changes from this PR branch
git checkout --ours src/services/helpContentService.js
git add src/services/helpContentService.js
```

**Then verify:** Check if any new badge references were added in main that need the relative path pattern applied.

---

### Option 2: Accept Main's Changes

**What it does:** Keep absolute badge paths from main branch
**Why NOT recommended:** Will reintroduce 404 errors in feature branch deployments

**Drawbacks:**
- ❌ 404 errors will return in feature branch deployments
- ❌ Absolute paths don't work across different deployment contexts
- ❌ Undoes the fix this PR provides

**How to resolve:**
```bash
# Keep main branch version (NOT RECOMMENDED)
git checkout --theirs src/services/helpContentService.js
git add src/services/helpContentService.js
```

---

### Option 3: Manual Merge (Most Thorough) 🔧

**What it does:** Carefully merge both changes, keeping relative paths while preserving any new content from main

**When to use:** If main branch added new help topics or badge references

**How to resolve:**
1. Open `src/services/helpContentService.js` in a text editor
2. Look for conflict markers: `<<<<<<<`, `=======`, `>>>>>>>`
3. For each badge path conflict:
- Keep the **relative path** version (without `/sgex/` prefix)
- Verify it matches pattern: `badge: 'cat-paw-*.svg'`
4. For any new content in main:
- Keep the new content
- But ensure any badge paths use relative format
5. Remove all conflict markers
6. Save the file
7. Test the changes
8. Stage the file: `git add src/services/helpContentService.js`

**Example resolution:**
```javascript
<<<<<<< HEAD (this PR branch)
badge: 'cat-paw-icon.svg'
=======
badge: '/sgex/cat-paw-icon.svg'
>>>>>>> origin/main

// RESOLVED: Keep relative path from PR branch
badge: 'cat-paw-icon.svg'
```

Expand Down Expand Up @@ -277,3 +148,4 @@ If you need help resolving this conflict, please:
4. If still unclear, ask for clarification with specific questions about the conflict

**Note:** This is a straightforward conflict with a clear recommended resolution. The relative path approach is tested and working in this PR.

14 changes: 14 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,20 @@ const user = validateAndCast<GitHubUser>('GitHubUser', userData);

The project uses `eslint-plugin-jsx-a11y` to enforce accessibility best practices. See [docs/accessibility-linting.md](docs/accessibility-linting.md) for detailed information about accessibility rules and how to fix common issues.

### Security Checks

The project includes comprehensive automated security checks that run on every PR build. These checks include:

- **NPM Audit** - Scans for known vulnerabilities in dependencies
- **Outdated Dependencies** - Identifies packages needing updates
- **ESLint Security Rules** - Detects security issues in code
- **Security Headers** - Verifies security header configuration
- **License Compliance** - Checks for restrictive licenses
- **Secret Scanning** - Detects hardcoded secrets
- **Framework Compliance** - Ensures security best practices

See [docs/security-checks.md](docs/security-checks.md) for detailed information about security checks and how to interpret results.

### Troubleshooting

If you encounter build or installation issues:
Expand Down
Loading