generated from nhcarrigan/template
ec58c9c843
CI / dependency-pin-check-typescript (push) Successful in 5s
CI / dependency-pin-check-python (push) Successful in 4s
CI / python (push) Successful in 9m28s
CI / typescript (push) Successful in 9m42s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 1m39s
## Summary This PR completes the bash script restructuring and adds comprehensive documentation across all script categories. ### Bash Restructuring - Moved cohort shell scripts (`remove_github_members.sh`, `update_github_teams.sh`) from `python/cohort/` into a new `bash/cohort/` directory - Moved existing bash utilities (`add-keys-to-git.sh`, `fix-yubikey-perms.sh`, `list-yubikey-ssh-keys.sh`) into a new `bash/yubikey/` subdirectory - Updated `run.sh` to support **Bash** as a third language option alongside TypeScript and Python - Bash scripts are run directly (no 1Password secret injection needed) - Category discovery and script listing works the same as for TS/Python - Removed dead "Root Scripts" logic that was no longer needed ### Documentation Added `README.md` files for all script categories that were missing them: - `bash/cohort/README.md` — cohort GitHub team management scripts - `bash/yubikey/README.md` — YubiKey SSH key and permission utilities - `typescript/src/crowdin/README.md` — Crowdin translation management scripts - `typescript/src/discord/README.md` — Discord bot utility scripts - `typescript/src/discourse/README.md` — Discourse forum management scripts - `typescript/src/gitea/README.md` — Gitea bulk repository operation scripts - `typescript/src/github/README.md` — GitHub API interaction scripts - `typescript/src/music/README.md` — Music file metadata tools - `typescript/src/s3/README.md` — S3-compatible object storage scripts - `typescript/src/security/README.md` — Security analysis and reporting scripts - `python/cohort/README.md` — Updated to remove moved shell scripts, fix usage commands Also updated project-level docs: - **`README.md`** — Corrected project structure, fixed running instructions (removed references to non-existent `make run-ts`/`make run-py` targets), added Bash prerequisites - **`CLAUDE.md`** — Updated project overview, structure, development standards, and script-adding guides to reflect the current state of the project ✨ This PR was created with help from Hikari~ 🌸 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Reviewed-on: #6 Co-authored-by: Hikari <hikari@nhcarrigan.com> Co-committed-by: Hikari <hikari@nhcarrigan.com>
284 lines
10 KiB
Markdown
284 lines
10 KiB
Markdown
# Ephemere Project Guidelines
|
|
|
|
This document contains project-specific instructions for working with the Ephemere codebase.
|
|
|
|
## Project Overview
|
|
|
|
Ephemere is a collection of ephemeral scripts for various tasks, written in TypeScript, Python, and Bash. It contains utilities for:
|
|
- S3 operations (upload, bulk upload, delete, content type correction)
|
|
- Discord bot utilities
|
|
- Discourse forum management
|
|
- Gitea/GitHub operations
|
|
- Security analysis tools
|
|
- Music-related scripts
|
|
- Cohort programme management (Python + Bash)
|
|
- YubiKey SSH key and permission utilities (Bash)
|
|
|
|
## Project Structure
|
|
|
|
```
|
|
ephemere/
|
|
├── typescript/ # TypeScript scripts
|
|
│ └── src/
|
|
│ ├── s3/ # S3 operations (upload, delete, bulk operations)
|
|
│ ├── discord/ # Discord bot and utilities
|
|
│ ├── discourse/ # Discourse forum management
|
|
│ ├── gitea/ # Gitea API interactions
|
|
│ ├── github/ # GitHub API interactions
|
|
│ ├── security/ # Security analysis tools
|
|
│ ├── music/ # Music-related utilities
|
|
│ └── utils/ # Shared utilities
|
|
├── python/
|
|
│ └── cohort/ # Cohort programme management scripts
|
|
├── bash/
|
|
│ ├── cohort/ # GitHub team management for cohorts
|
|
│ └── yubikey/ # YubiKey SSH key and permission utilities
|
|
├── data/ # Input/output data files (gitignored)
|
|
└── prod.env # 1Password vault references (safe to commit)
|
|
```
|
|
|
|
## Development Standards
|
|
|
|
### TypeScript Scripts
|
|
- All TypeScript scripts must follow Naomi's Node.js project standards
|
|
- Use `@nhcarrigan/typescript-config` and `@nhcarrigan/eslint-config`
|
|
- Run scripts using the interactive runner: `make run` (select TypeScript → category → script)
|
|
- Interactive scripts should use `@inquirer/prompts` for user input
|
|
|
|
### Python Scripts
|
|
- Use `uv` for package management
|
|
- Linting and formatting with `ruff`
|
|
- Scripts live in subdirectories of `python/` (e.g. `python/cohort/`)
|
|
- Run scripts using the interactive runner: `make run` (select Python → category → script)
|
|
|
|
### Bash Scripts
|
|
- Scripts live in subdirectories of `bash/` (e.g. `bash/cohort/`, `bash/yubikey/`)
|
|
- Run scripts using the interactive runner: `make run` (select Bash → category → script)
|
|
- Or run directly: `bash bash/<category>/<script>.sh`
|
|
- Bash scripts do not use 1Password injection (they use `gh` CLI auth or system tools)
|
|
|
|
### S3 Scripts Specifics
|
|
All S3 scripts in `typescript/src/s3/` follow these patterns:
|
|
- Use environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_ENDPOINT`
|
|
- Interactive prompts using `@inquirer/prompts`
|
|
- Progress bars using `cli-progress` for bulk operations
|
|
- Proper error handling with success/error counts
|
|
- ESLint disable comments for AWS SDK naming conventions
|
|
- No CLI arguments - everything is prompted interactively
|
|
|
|
## Running Scripts
|
|
|
|
Always use the interactive runner to run scripts (it handles 1Password integration for TypeScript and Python):
|
|
|
|
```bash
|
|
make run # Interactive menu to select language, category, and script
|
|
```
|
|
|
|
Or run directly:
|
|
```bash
|
|
# TypeScript (from project root)
|
|
cd typescript && op run --env-file=../prod.env -- pnpm tsx src/<category>/<script>.ts
|
|
|
|
# Python (from project root)
|
|
cd python && op run --env-file=../prod.env -- uv run python <category>/<script>.py
|
|
|
|
# Bash (no 1Password needed)
|
|
bash bash/<category>/<script>.sh
|
|
```
|
|
|
|
## Script Patterns
|
|
|
|
### TypeScript Script Template
|
|
```typescript
|
|
/**
|
|
* @copyright NHCarrigan
|
|
* @license Naomi's Public License
|
|
* @author Naomi Carrigan
|
|
*/
|
|
import { input, confirm, select } from "@inquirer/prompts";
|
|
|
|
// Environment variable checks
|
|
const requiredVar = process.env.REQUIRED_VAR;
|
|
if (requiredVar === undefined) {
|
|
throw new Error("REQUIRED_VAR is not set");
|
|
}
|
|
|
|
// Interactive prompts
|
|
const userInput = await input({
|
|
message: "Enter your input:",
|
|
validate: (value) => {
|
|
if (!value.trim()) {
|
|
return "Input cannot be empty";
|
|
}
|
|
return true;
|
|
},
|
|
});
|
|
|
|
// Main logic here
|
|
console.log("Processing...");
|
|
|
|
// Always provide feedback
|
|
console.log("✅ Operation completed successfully!");
|
|
```
|
|
|
|
### Python Script Template
|
|
```python
|
|
#!/usr/bin/env python3
|
|
"""
|
|
Script description here.
|
|
|
|
@copyright NHCarrigan
|
|
@license Naomi's Public License
|
|
@author Naomi Carrigan
|
|
"""
|
|
import os
|
|
import sys
|
|
from typing import Optional
|
|
|
|
def main() -> None:
|
|
"""Main function."""
|
|
# Environment variable checks
|
|
required_var = os.getenv("REQUIRED_VAR")
|
|
if not required_var:
|
|
print("Error: REQUIRED_VAR is not set")
|
|
sys.exit(1)
|
|
|
|
# Interactive input (if needed)
|
|
user_input = input("Enter your input: ").strip()
|
|
if not user_input:
|
|
print("Error: Input cannot be empty")
|
|
sys.exit(1)
|
|
|
|
# Main logic here
|
|
print("Processing...")
|
|
|
|
# Always provide feedback
|
|
print("✅ Operation completed successfully!")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|
|
```
|
|
|
|
## Environment Variables
|
|
|
|
All secrets are managed through 1Password and referenced in `prod.env`:
|
|
- AWS credentials for S3 operations
|
|
- Discord bot tokens
|
|
- GitHub/Gitea API tokens
|
|
- Discourse API credentials
|
|
|
|
The `prod.env` file contains 1Password vault references (like `op://Private/Hetzner/S3 Endpoint`) and is safe to commit.
|
|
|
|
## Important Notes
|
|
|
|
1. **No hardcoded values** - All configuration should come from environment variables
|
|
2. **Interactive scripts** - Scripts should prompt for all required input, not use CLI arguments
|
|
3. **Progress feedback** - Long-running operations should show progress bars
|
|
4. **Error handling** - Always track and report success/failure counts
|
|
5. **Consistent patterns** - Follow the existing script patterns in each category
|
|
|
|
## Best Practices
|
|
|
|
### Error Handling
|
|
- Always validate environment variables at script start
|
|
- Provide clear error messages that help users fix the issue
|
|
- Use try-catch blocks for external API calls
|
|
- Track success/failure counts for bulk operations
|
|
- Exit with appropriate status codes (0 for success, 1 for errors)
|
|
|
|
### User Experience
|
|
- Use emojis in console output for visual feedback (✅ ❌ ⚠️ 🚀 📦 etc.)
|
|
- Show progress bars for operations with multiple items
|
|
- Confirm destructive operations (require typing confirmation + yes/no)
|
|
- Provide summaries at the end of bulk operations
|
|
- Keep output concise but informative
|
|
|
|
### Code Quality
|
|
- Add JSDoc comments for TypeScript functions
|
|
- Use type annotations in Python
|
|
- Follow the established linting rules (no overrides without good reason)
|
|
- Keep functions focused and single-purpose
|
|
- Extract reusable logic to utility functions
|
|
|
|
### Security
|
|
- Never log sensitive information (tokens, passwords, keys)
|
|
- Validate all user inputs
|
|
- Use parameterized queries for any database operations
|
|
- Follow the principle of least privilege for API tokens
|
|
- Sanitize file paths and names
|
|
|
|
## Common Tasks
|
|
|
|
### Adding a new S3 script
|
|
1. Create the script in `typescript/src/s3/`
|
|
2. Follow the pattern of existing S3 scripts (see deleteContents.ts)
|
|
3. Use environment variables: `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, `S3_ENDPOINT`
|
|
4. Use @inquirer/prompts for all user input (no CLI arguments)
|
|
5. Include proper error handling and progress bars for bulk operations
|
|
6. Add ESLint disable comments for AWS SDK naming conventions
|
|
|
|
### Adding a new Discord script
|
|
1. Create the script in `typescript/src/discord/`
|
|
2. Use environment variables: `DISCORD_TOKEN`, `DISCORD_CLIENT_ID`, etc.
|
|
3. Follow Discord.js best practices
|
|
4. Use @inquirer/prompts for any configuration input
|
|
5. Handle rate limits and API errors gracefully
|
|
|
|
### Adding a new GitHub/Gitea script
|
|
1. Create the script in `typescript/src/github/` or `typescript/src/gitea/`
|
|
2. Use environment variables: `GITHUB_TOKEN` or `GITEA_TOKEN`
|
|
3. Use the Octokit library for GitHub operations
|
|
4. Include proper pagination for list operations
|
|
5. Handle API rate limits appropriately
|
|
|
|
### Adding a new Discourse script
|
|
1. Create the script in `typescript/src/discourse/`
|
|
2. Use environment variables: `DISCOURSE_URL`, `DISCOURSE_API_KEY`, `DISCOURSE_API_USERNAME`
|
|
3. Follow the Discourse API documentation
|
|
4. Use @inquirer/prompts for interactive inputs
|
|
5. Handle API errors and rate limits
|
|
|
|
### Adding a new Security script
|
|
1. Create the script in `typescript/src/security/`
|
|
2. Use environment variables for any API tokens (e.g., `DOJO_TOKEN` for DefectDojo)
|
|
3. Follow security best practices - never log sensitive data
|
|
4. Include proper validation for all inputs
|
|
5. Consider adding audit logs for security operations
|
|
|
|
### Adding a new Python script
|
|
1. Create the script in the appropriate subdirectory of `python/` (e.g. `python/cohort/`)
|
|
2. Use type hints for all functions and variables
|
|
3. Follow PEP 8 style guide (enforced by ruff)
|
|
4. Add the script to `requirements.txt` if it needs new dependencies
|
|
5. Use `argparse` for CLI arguments if needed (though prefer interactive)
|
|
6. Include docstrings for all functions and classes
|
|
|
|
### Adding a new utility function
|
|
1. TypeScript utilities go in `typescript/src/utils/`
|
|
2. Python utilities can be imported from a shared module
|
|
3. Utilities should be pure functions when possible
|
|
4. Include comprehensive JSDoc/docstring documentation
|
|
5. Add unit tests if the utility is complex
|
|
|
|
### Adding a new script category
|
|
1. Create a new directory under `typescript/src/`, `python/`, or `bash/` as appropriate
|
|
2. Follow the naming convention (lowercase, descriptive)
|
|
3. Create at least one example script showing the pattern
|
|
4. Create a `README.md` in the new directory documenting each script
|
|
5. Update this CLAUDE.md with specific guidelines for the category
|
|
6. Add any new environment variables to prod.env with 1Password references
|
|
|
|
## Testing
|
|
|
|
Before committing:
|
|
```bash
|
|
make lint # Run all linters
|
|
make build # Type check TypeScript
|
|
make test # Run tests (if any)
|
|
```
|
|
|
|
## Troubleshooting
|
|
|
|
- If a script fails with "not set" errors, ensure you're running through the Makefile or with `op run`
|
|
- For S3 scripts, verify your 1Password vault has the correct S3 endpoint, access key, and secret key
|
|
- TypeScript import errors: ensure you use `.js` extensions in imports (even for `.ts` files) |