Skip to content

Commit da8dd9a

Browse files
committed
init
0 parents  commit da8dd9a

File tree

13 files changed

+661
-0
lines changed

13 files changed

+661
-0
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
* @nodejs/web
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
import { readFile } from 'node:fs/promises';
2+
3+
const CONFIG = {
4+
FILE: 'MEMBERS.md',
5+
HEADER: '## Node.js Website Team (`@nodejs/nodejs-website`)',
6+
INACTIVE_MONTHS: 12,
7+
ISSUE_TITLE: 'Inactive Collaborator Report',
8+
ISSUE_LABELS: ['meta', 'inactive-collaborator-report'],
9+
};
10+
11+
// Get date N months ago in YYYY-MM-DD format
12+
const getDateMonthsAgo = (months = CONFIG.INACTIVE_MONTHS) => {
13+
const date = new Date();
14+
date.setMonth(date.getMonth() - months);
15+
return date.toISOString().split('T')[0];
16+
};
17+
18+
// Check if there's already an open issue
19+
async function hasOpenIssue(github, context) {
20+
const { owner, repo } = context.repo;
21+
const { data: issues } = await github.rest.issues.listForRepo({
22+
owner,
23+
repo,
24+
state: 'open',
25+
labels: CONFIG.ISSUE_LABELS[1],
26+
per_page: 1,
27+
});
28+
29+
return issues.length > 0;
30+
}
31+
32+
// Parse collaborator usernames from governance file
33+
async function parseCollaborators() {
34+
const content = await readFile(CONFIG.FILE, 'utf8');
35+
const lines = content.split('\n');
36+
const collaborators = [];
37+
38+
const startIndex =
39+
lines.findIndex(l => l.startsWith(CONFIG.HEADER)) + 1;
40+
if (startIndex <= 0) return collaborators;
41+
42+
for (let i = startIndex; i < lines.length; i++) {
43+
const line = lines[i];
44+
if (line.startsWith('#')) break;
45+
46+
const match = line.match(/^\s*-\s*\[([^\]]+)\]/);
47+
if (match) collaborators.push(match[1]);
48+
}
49+
50+
return collaborators;
51+
}
52+
53+
// Check if users have been active since cutoff date
54+
async function getInactiveUsers(github, usernames, repo, cutoffDate) {
55+
const inactiveUsers = [];
56+
57+
for (const username of usernames) {
58+
// Check commits
59+
const { data: commits } = await github.rest.search.commits({
60+
q: `author:${username} repo:${repo} committer-date:>=${cutoffDate}`,
61+
per_page: 1,
62+
});
63+
64+
// Check issues and PRs
65+
const { data: issues } = await github.rest.search.issuesAndPullRequests({
66+
q: `involves:${username} repo:${repo} updated:>=${cutoffDate}`,
67+
per_page: 1,
68+
});
69+
70+
// User is inactive if they have no commits AND no issues/PRs
71+
if (commits.total_count === 0 && issues.total_count === 0) {
72+
inactiveUsers.push(username);
73+
}
74+
}
75+
76+
return inactiveUsers;
77+
}
78+
79+
// Generate report for inactive members
80+
function formatReport(inactiveMembers, cutoffDate) {
81+
if (!inactiveMembers.length) return null;
82+
83+
const today = getDateMonthsAgo(0);
84+
return `# Inactive Collaborators Report
85+
86+
Last updated: ${today}
87+
Checking for inactivity since: ${cutoffDate}
88+
89+
## Inactive Collaborators (${inactiveMembers.length})
90+
91+
| Login |
92+
| ----- |
93+
${inactiveMembers.map(m => `| @${m} |`).join('\n')}
94+
95+
## What happens next?
96+
97+
@nodejs/nodejs-website should review this list and contact inactive collaborators to confirm their continued interest in participating in the project.`;
98+
}
99+
100+
async function createIssue(github, context, report) {
101+
if (!report) return;
102+
103+
const { owner, repo } = context.repo;
104+
await github.rest.issues.create({
105+
owner,
106+
repo,
107+
title: CONFIG.ISSUE_TITLE,
108+
body: report,
109+
labels: CONFIG.ISSUE_LABELS,
110+
});
111+
}
112+
113+
export default async function (github, context) {
114+
// Check for existing open issue first - exit early if one exists
115+
if (await hasOpenIssue(github, context)) {
116+
return;
117+
}
118+
119+
const cutoffDate = getDateMonthsAgo();
120+
const collaborators = await parseCollaborators();
121+
122+
const inactiveMembers = await getInactiveUsers(
123+
github,
124+
collaborators,
125+
`${context.repo.owner}/${context.repo.repo}`,
126+
cutoffDate
127+
);
128+
const report = formatReport(inactiveMembers, cutoffDate);
129+
130+
await createIssue(github, context, report);
131+
}

.github/workflows/codeql.yml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# For most projects, this workflow file will not need changing; you simply need
2+
# to commit it to your repository.
3+
#
4+
# You may wish to alter this file to override the set of languages analyzed,
5+
# or to provide custom queries or build logic.
6+
#
7+
# ******** NOTE ********
8+
# We have attempted to detect the languages in your repository. Please check
9+
# the `language` matrix defined below to confirm you have the correct set of
10+
# supported CodeQL languages.
11+
#
12+
name: 'CodeQL'
13+
14+
on:
15+
push:
16+
branches: ['main']
17+
pull_request:
18+
# The branches below must be a subset of the branches above
19+
branches: ['main']
20+
schedule:
21+
- cron: '0 0 * * 1'
22+
workflow_call:
23+
24+
permissions:
25+
contents: read
26+
27+
jobs:
28+
analyze:
29+
name: Analyze
30+
runs-on: ubuntu-latest
31+
permissions:
32+
actions: read
33+
contents: read
34+
security-events: write
35+
36+
strategy:
37+
fail-fast: false
38+
matrix:
39+
language: ['javascript', 'typescript']
40+
# CodeQL supports [ $supported-codeql-languages ]
41+
# Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support
42+
43+
steps:
44+
- name: Harden Runner
45+
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
46+
with:
47+
egress-policy: audit
48+
49+
- name: Checkout repository
50+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
51+
52+
# Initializes the CodeQL tools for scanning.
53+
- name: Initialize CodeQL
54+
uses: github/codeql-action/init@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
55+
with:
56+
languages: ${{ matrix.language }}
57+
# If you wish to specify custom queries, you can do so here or in a config file.
58+
# By default, queries listed here will override any specified in a config file.
59+
# Prefix the list here with "+" to use these queries and those in the config file.
60+
61+
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
62+
# If this step fails, then you should remove it and run the build manually (see below)
63+
- name: Autobuild
64+
uses: github/codeql-action/autobuild@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
65+
66+
# ℹ️ Command-line programs to run using the OS shell.
67+
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
68+
69+
# If the Autobuild fails above, remove it and uncomment the following three lines.
70+
# modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance.
71+
72+
# - run: |
73+
# echo "Run, Build Application using script"
74+
# ./location_of_script_within_repo/buildscript.sh
75+
76+
- name: Perform CodeQL Analysis
77+
uses: github/codeql-action/analyze@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
78+
with:
79+
category: '/language:${{matrix.language}}'
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: 'Dependency Review'
2+
3+
on:
4+
pull_request:
5+
workflow_call:
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
dependency-review:
12+
runs-on: ubuntu-latest
13+
steps:
14+
- name: 'Checkout Repository'
15+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
16+
17+
- name: 'Dependency Review'
18+
uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
name: Find inactive collaborators
2+
3+
on:
4+
schedule:
5+
- cron: '0 0 1 * *' # Runs at 00:00 UTC on the 1st day of every month
6+
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
issues: write
12+
13+
jobs:
14+
find:
15+
if: github.repository == 'nodejs/nodejs.org'
16+
runs-on: ubuntu-latest
17+
18+
steps:
19+
- name: Harden Runner
20+
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
21+
with:
22+
egress-policy: audit
23+
24+
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
25+
26+
- name: Report inactive collaborators
27+
id: inactive
28+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1
29+
with:
30+
script: |
31+
const { default: report } = await import("${{github.workspace}}/.github/scripts/report-inactive-collaborators.mjs");
32+
report(github, context);

.github/workflows/scorecard.yml

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# This workflow uses actions that are not certified by GitHub. They are provided
2+
# by a third party and are governed by separate terms of service, privacy
3+
# policy and support documentation.
4+
5+
name: OpenSSF Scorecard Review
6+
on:
7+
# For Branch-Protection check. Only the default branch is supported. See
8+
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
9+
branch_protection_rule:
10+
# To guarantee that the Maintained check is occasionally updated. See
11+
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
12+
schedule:
13+
- cron: '20 7 * * 2'
14+
push:
15+
branches:
16+
- main
17+
workflow_call:
18+
19+
# Declare default permissions as read only.
20+
permissions: read-all
21+
22+
jobs:
23+
analysis:
24+
name: Scorecard analysis
25+
runs-on: ubuntu-latest
26+
permissions:
27+
# Needed to upload the results to code-scanning dashboard.
28+
security-events: write
29+
# Needed to publish results and get a badge (see publish_results below).
30+
id-token: write
31+
contents: read
32+
actions: read
33+
34+
steps:
35+
- name: Harden Runner
36+
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
37+
with:
38+
egress-policy: audit
39+
40+
- name: Git Checkout
41+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
42+
with:
43+
persist-credentials: false
44+
45+
- name: Run Scorecard Analysis
46+
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
47+
with:
48+
results_file: results.sarif
49+
results_format: sarif
50+
publish_results: true
51+
52+
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
53+
# format to the repository Actions tab.
54+
- name: Upload Artifacts
55+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
56+
with:
57+
name: SARIF file
58+
path: results.sarif
59+
retention-days: 5
60+
61+
# Upload the results to GitHub's code scanning dashboard.
62+
- name: Upload Scan Results
63+
uses: github/codeql-action/upload-sarif@ff0a06e83cb2de871e5a09832bc6a81e7276941f # v3.28.18
64+
with:
65+
sarif_file: results.sarif

CODE_OF_CONDUCT.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Code of Conduct
2+
3+
- [Node.js Code of Conduct](https://github.com/nodejs/admin/blob/HEAD/CODE_OF_CONDUCT.md)
4+
- [Node.js Moderation Policy](https://github.com/nodejs/admin/blob/HEAD/Moderation-Policy.md)

0 commit comments

Comments
 (0)