generated from nhcarrigan/template
6169eb4577
CI / dependency-pin-check-typescript (push) Successful in 4s
CI / dependency-pin-check-python (push) Successful in 4s
Security Scan and Upload / Security & DefectDojo Upload (push) Successful in 52s
CI / python (push) Successful in 9m22s
CI / typescript (push) Successful in 9m43s
### Explanation _No response_ ### Issue _No response_ ### Attestations - [ ] I have read and agree to the [Code of Conduct](https://docs.nhcarrigan.com/community/coc/) - [ ] I have read and agree to the [Community Guidelines](https://docs.nhcarrigan.com/community/guide/). - [ ] My contribution complies with the [Contributor Covenant](https://docs.nhcarrigan.com/dev/covenant/). ### Dependencies - [ ] I have pinned the dependencies to a specific patch version. ### Style - [ ] I have run the linter and resolved any errors. - [ ] My pull request uses an appropriate title, matching the conventional commit standards. - [ ] My scope of feat/fix/chore/etc. correctly matches the nature of changes in my pull request. ### Tests - [ ] My contribution adds new code, and I have added tests to cover it. - [ ] My contribution modifies existing code, and I have updated the tests to reflect these changes. - [ ] All new and existing tests pass locally with my changes. - [ ] Code coverage remains at or above the configured threshold. ### Documentation _No response_ ### Versioning _No response_ Reviewed-on: #3 Co-authored-by: Naomi Carrigan <commits@nhcarrigan.com> Co-committed-by: Naomi Carrigan <commits@nhcarrigan.com>
9.0 KiB
9.0 KiB
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 and Python. 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
- Various utility functions
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
│ └── data/ # Data files for S3 uploads
├── python/ # Python scripts
└── 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-configand@nhcarrigan/eslint-config - Run scripts using the Makefile:
make run-ts src/path/to/script.ts - Interactive scripts should use
@inquirer/promptsfor user input
Python Scripts
- Use
uvfor package management - Linting and formatting with
ruff - Run scripts using the Makefile:
make run-py script_name.py
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-progressfor 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 Makefile commands to run scripts (they handle 1Password integration):
# TypeScript scripts
make run-ts src/s3/deleteContents.ts
make run-ts src/discord/bot.ts
# Python scripts
make run-py analyse_availability.py
Or use the interactive runner:
make run # Interactive menu to select language, category, and script
Script Patterns
TypeScript Script Template
/**
* @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
#!/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
- No hardcoded values - All configuration should come from environment variables
- Interactive scripts - Scripts should prompt for all required input, not use CLI arguments
- Progress feedback - Long-running operations should show progress bars
- Error handling - Always track and report success/failure counts
- 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
- Create the script in
typescript/src/s3/ - Follow the pattern of existing S3 scripts (see deleteContents.ts)
- Use environment variables:
AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,S3_ENDPOINT - Use @inquirer/prompts for all user input (no CLI arguments)
- Include proper error handling and progress bars for bulk operations
- Add ESLint disable comments for AWS SDK naming conventions
Adding a new Discord script
- Create the script in
typescript/src/discord/ - Use environment variables:
DISCORD_TOKEN,DISCORD_CLIENT_ID, etc. - Follow Discord.js best practices
- Use @inquirer/prompts for any configuration input
- Handle rate limits and API errors gracefully
Adding a new GitHub/Gitea script
- Create the script in
typescript/src/github/ortypescript/src/gitea/ - Use environment variables:
GITHUB_TOKENorGITEA_TOKEN - Use the Octokit library for GitHub operations
- Include proper pagination for list operations
- Handle API rate limits appropriately
Adding a new Discourse script
- Create the script in
typescript/src/discourse/ - Use environment variables:
DISCOURSE_URL,DISCOURSE_API_KEY,DISCOURSE_API_USERNAME - Follow the Discourse API documentation
- Use @inquirer/prompts for interactive inputs
- Handle API errors and rate limits
Adding a new Security script
- Create the script in
typescript/src/security/ - Use environment variables for any API tokens (e.g.,
DOJO_TOKENfor DefectDojo) - Follow security best practices - never log sensitive data
- Include proper validation for all inputs
- Consider adding audit logs for security operations
Adding a new Python script
- Create the script in
python/ - Use type hints for all functions and variables
- Follow PEP 8 style guide (enforced by ruff)
- Add the script to
requirements.txtif it needs new dependencies - Use
argparsefor CLI arguments if needed (though prefer interactive) - Include docstrings for all functions and classes
Adding a new utility function
- TypeScript utilities go in
typescript/src/utils/ - Python utilities can be imported from a shared module
- Utilities should be pure functions when possible
- Include comprehensive JSDoc/docstring documentation
- Add unit tests if the utility is complex
Adding a new script category
- Create a new directory under
typescript/src/or inpython/ - Follow the naming convention (lowercase, descriptive)
- Create at least one example script showing the pattern
- Update this CLAUDE.md with specific guidelines for the category
- Add any new environment variables to prod.env with 1Password references
Testing
Before committing:
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
.jsextensions in imports (even for.tsfiles)