@softspark/ai-toolkit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +412 -0
- package/CHANGELOG.md +68 -0
- package/LICENSE +21 -0
- package/README.md +632 -0
- package/action.yml +53 -0
- package/app/.claude-plugin/plugin.json +44 -0
- package/app/ARCHITECTURE.md +306 -0
- package/app/CLAUDE.md.template +23 -0
- package/app/agents/ai-engineer.md +128 -0
- package/app/agents/backend-specialist.md +193 -0
- package/app/agents/business-intelligence.md +54 -0
- package/app/agents/chaos-monkey.md +67 -0
- package/app/agents/chief-of-staff.md +51 -0
- package/app/agents/code-archaeologist.md +127 -0
- package/app/agents/code-reviewer.md +184 -0
- package/app/agents/command-expert.md +131 -0
- package/app/agents/data-analyst.md +205 -0
- package/app/agents/data-scientist.md +151 -0
- package/app/agents/database-architect.md +317 -0
- package/app/agents/debugger.md +238 -0
- package/app/agents/devops-implementer.md +194 -0
- package/app/agents/documenter.md +364 -0
- package/app/agents/explorer-agent.md +145 -0
- package/app/agents/fact-checker.md +172 -0
- package/app/agents/frontend-specialist.md +209 -0
- package/app/agents/game-developer.md +216 -0
- package/app/agents/incident-responder.md +226 -0
- package/app/agents/infrastructure-architect.md +127 -0
- package/app/agents/infrastructure-validator.md +247 -0
- package/app/agents/llm-ops-engineer.md +237 -0
- package/app/agents/mcp-expert.md +228 -0
- package/app/agents/mcp-server-architect.md +195 -0
- package/app/agents/mcp-testing-engineer.md +292 -0
- package/app/agents/meta-architect.md +58 -0
- package/app/agents/ml-engineer.md +136 -0
- package/app/agents/mobile-developer.md +190 -0
- package/app/agents/night-watchman.md +55 -0
- package/app/agents/nlp-engineer.md +154 -0
- package/app/agents/orchestrator.md +437 -0
- package/app/agents/performance-optimizer.md +254 -0
- package/app/agents/predictive-analyst.md +57 -0
- package/app/agents/product-manager.md +194 -0
- package/app/agents/project-planner.md +287 -0
- package/app/agents/prompt-engineer.md +103 -0
- package/app/agents/qa-automation-engineer.md +182 -0
- package/app/agents/rag-engineer.md +201 -0
- package/app/agents/research-synthesizer.md +138 -0
- package/app/agents/search-specialist.md +101 -0
- package/app/agents/security-architect.md +62 -0
- package/app/agents/security-auditor.md +293 -0
- package/app/agents/seo-specialist.md +111 -0
- package/app/agents/system-governor.md +57 -0
- package/app/agents/tech-lead.md +62 -0
- package/app/agents/technical-researcher.md +103 -0
- package/app/agents/test-engineer.md +264 -0
- package/app/constitution.md +38 -0
- package/app/hooks/_profile-check.sh +11 -0
- package/app/hooks/guard-destructive.sh +74 -0
- package/app/hooks/guard-path.sh +73 -0
- package/app/hooks/post-tool-use.sh +35 -0
- package/app/hooks/pre-compact.sh +31 -0
- package/app/hooks/quality-check.sh +22 -0
- package/app/hooks/quality-gate.sh +49 -0
- package/app/hooks/save-session.sh +24 -0
- package/app/hooks/session-end.sh +37 -0
- package/app/hooks/session-start.sh +29 -0
- package/app/hooks/subagent-start.sh +16 -0
- package/app/hooks/subagent-stop.sh +16 -0
- package/app/hooks/track-usage.sh +50 -0
- package/app/hooks/user-prompt-submit.sh +25 -0
- package/app/hooks.json +178 -0
- package/app/mcp-defaults.json +23 -0
- package/app/output-styles/golden-rules.md +43 -0
- package/app/plugins/README.md +19 -0
- package/app/plugins/csharp-pack/README.md +11 -0
- package/app/plugins/csharp-pack/plugin.json +18 -0
- package/app/plugins/enterprise-pack/README.md +16 -0
- package/app/plugins/enterprise-pack/hooks/output-style.sh +6 -0
- package/app/plugins/enterprise-pack/hooks/status-line.sh +8 -0
- package/app/plugins/enterprise-pack/plugin.json +24 -0
- package/app/plugins/frontend-pack/README.md +14 -0
- package/app/plugins/frontend-pack/plugin.json +22 -0
- package/app/plugins/java-pack/README.md +11 -0
- package/app/plugins/java-pack/plugin.json +18 -0
- package/app/plugins/kotlin-pack/README.md +11 -0
- package/app/plugins/kotlin-pack/plugin.json +18 -0
- package/app/plugins/memory-pack/README.md +24 -0
- package/app/plugins/memory-pack/hooks/observation-capture.sh +67 -0
- package/app/plugins/memory-pack/hooks/session-summary.sh +71 -0
- package/app/plugins/memory-pack/plugin.json +22 -0
- package/app/plugins/memory-pack/scripts/init_db.py +81 -0
- package/app/plugins/memory-pack/scripts/strip_private.py +22 -0
- package/app/plugins/memory-pack/skills/mem-search/SKILL.md +70 -0
- package/app/plugins/research-pack/README.md +14 -0
- package/app/plugins/research-pack/plugin.json +22 -0
- package/app/plugins/ruby-pack/README.md +11 -0
- package/app/plugins/ruby-pack/plugin.json +18 -0
- package/app/plugins/rust-pack/README.md +11 -0
- package/app/plugins/rust-pack/plugin.json +18 -0
- package/app/plugins/security-pack/README.md +15 -0
- package/app/plugins/security-pack/plugin.json +23 -0
- package/app/plugins/swift-pack/README.md +11 -0
- package/app/plugins/swift-pack/plugin.json +18 -0
- package/app/rules/claude-toolkit-rules.md +21 -0
- package/app/rules/git-conventions.md +5 -0
- package/app/rules/quality-gates.md +10 -0
- package/app/skills/_lib/__init__.py +1 -0
- package/app/skills/_lib/detect_utils.py +150 -0
- package/app/skills/agent-creator/SKILL.md +82 -0
- package/app/skills/analyze/SKILL.md +92 -0
- package/app/skills/analyze/scripts/complexity.py +165 -0
- package/app/skills/api-patterns/SKILL.md +305 -0
- package/app/skills/app-builder/SKILL.md +187 -0
- package/app/skills/architecture-audit/SKILL.md +141 -0
- package/app/skills/architecture-decision/SKILL.md +55 -0
- package/app/skills/architecture-decision/templates/adr-template.md +36 -0
- package/app/skills/biz-scan/SKILL.md +30 -0
- package/app/skills/briefing/SKILL.md +27 -0
- package/app/skills/build/SKILL.md +97 -0
- package/app/skills/build/scripts/detect-build.py +151 -0
- package/app/skills/chaos/SKILL.md +32 -0
- package/app/skills/ci/SKILL.md +77 -0
- package/app/skills/ci/scripts/ci-detect.py +135 -0
- package/app/skills/ci/templates/github-actions-node.yml +38 -0
- package/app/skills/ci/templates/github-actions-python.yml +42 -0
- package/app/skills/ci-cd-patterns/SKILL.md +299 -0
- package/app/skills/clean-code/SKILL.md +110 -0
- package/app/skills/clean-code/reference/dart.md +18 -0
- package/app/skills/clean-code/reference/go.md +23 -0
- package/app/skills/clean-code/reference/php.md +32 -0
- package/app/skills/clean-code/reference/python.md +180 -0
- package/app/skills/clean-code/reference/typescript.md +26 -0
- package/app/skills/command-creator/SKILL.md +83 -0
- package/app/skills/commit/SKILL.md +98 -0
- package/app/skills/commit/scripts/pre-commit-check.py +87 -0
- package/app/skills/commit/templates/conventional-commit.md +52 -0
- package/app/skills/csharp-patterns/SKILL.md +450 -0
- package/app/skills/database-patterns/SKILL.md +297 -0
- package/app/skills/debug/SKILL.md +154 -0
- package/app/skills/debug/scripts/error-parser.py +187 -0
- package/app/skills/debugging-tactics/SKILL.md +136 -0
- package/app/skills/deploy/SKILL.md +130 -0
- package/app/skills/deploy/scripts/pre_deploy_check.py +171 -0
- package/app/skills/deploy/templates/deployment-checklist.md +31 -0
- package/app/skills/design-an-interface/SKILL.md +105 -0
- package/app/skills/design-engineering/SKILL.md +260 -0
- package/app/skills/docker-devops/SKILL.md +303 -0
- package/app/skills/docs/SKILL.md +145 -0
- package/app/skills/docs/scripts/doc-inventory.py +176 -0
- package/app/skills/docs/templates/adr-template.md +36 -0
- package/app/skills/docs/templates/readme-template.md +67 -0
- package/app/skills/documentation-standards/SKILL.md +191 -0
- package/app/skills/ecommerce-patterns/SKILL.md +209 -0
- package/app/skills/evaluate/SKILL.md +132 -0
- package/app/skills/evolve/SKILL.md +27 -0
- package/app/skills/explain/SKILL.md +54 -0
- package/app/skills/explain/scripts/dependency-graph.py +215 -0
- package/app/skills/explore/SKILL.md +112 -0
- package/app/skills/explore/scripts/visualize.py +117 -0
- package/app/skills/fix/SKILL.md +78 -0
- package/app/skills/fix/scripts/error-classifier.py +191 -0
- package/app/skills/flutter-patterns/SKILL.md +254 -0
- package/app/skills/git-mastery/SKILL.md +70 -0
- package/app/skills/grill-me/SKILL.md +38 -0
- package/app/skills/health/SKILL.md +91 -0
- package/app/skills/health/scripts/health_check.py +162 -0
- package/app/skills/hive-mind/SKILL.md +56 -0
- package/app/skills/hook-creator/SKILL.md +107 -0
- package/app/skills/index/SKILL.md +74 -0
- package/app/skills/instinct-review/SKILL.md +77 -0
- package/app/skills/java-patterns/SKILL.md +442 -0
- package/app/skills/kotlin-patterns/SKILL.md +446 -0
- package/app/skills/lint/SKILL.md +103 -0
- package/app/skills/lint/scripts/detect-linters.py +112 -0
- package/app/skills/mcp-patterns/SKILL.md +270 -0
- package/app/skills/mem-search/SKILL.md +70 -0
- package/app/skills/migrate/SKILL.md +90 -0
- package/app/skills/migrate/scripts/migration-status.py +195 -0
- package/app/skills/migration-patterns/SKILL.md +260 -0
- package/app/skills/night-watch/SKILL.md +28 -0
- package/app/skills/observability-patterns/SKILL.md +203 -0
- package/app/skills/onboard/SKILL.md +76 -0
- package/app/skills/orchestrate/SKILL.md +86 -0
- package/app/skills/panic/SKILL.md +30 -0
- package/app/skills/performance-profiling/SKILL.md +59 -0
- package/app/skills/plan/SKILL.md +110 -0
- package/app/skills/plan/templates/plan-template.md +40 -0
- package/app/skills/plan-writing/SKILL.md +201 -0
- package/app/skills/plugin-creator/SKILL.md +78 -0
- package/app/skills/pr/SKILL.md +129 -0
- package/app/skills/pr/scripts/pr-summary.py +175 -0
- package/app/skills/prd-to-issues/SKILL.md +108 -0
- package/app/skills/prd-to-plan/SKILL.md +120 -0
- package/app/skills/predict/SKILL.md +30 -0
- package/app/skills/qa-session/SKILL.md +110 -0
- package/app/skills/rag-patterns/SKILL.md +203 -0
- package/app/skills/refactor/SKILL.md +124 -0
- package/app/skills/refactor/scripts/refactor-scan.py +210 -0
- package/app/skills/refactor-plan/SKILL.md +112 -0
- package/app/skills/repeat/SKILL.md +149 -0
- package/app/skills/research-mastery/SKILL.md +56 -0
- package/app/skills/review/SKILL.md +141 -0
- package/app/skills/review/scripts/diff-analyzer.py +170 -0
- package/app/skills/rollback/SKILL.md +87 -0
- package/app/skills/rollback/scripts/rollback_info.py +149 -0
- package/app/skills/ruby-patterns/SKILL.md +454 -0
- package/app/skills/rust-patterns/SKILL.md +446 -0
- package/app/skills/search/SKILL.md +64 -0
- package/app/skills/security-patterns/SKILL.md +91 -0
- package/app/skills/security-patterns/reference/authentication.md +37 -0
- package/app/skills/security-patterns/reference/authorization.md +22 -0
- package/app/skills/security-patterns/reference/input-validation.md +30 -0
- package/app/skills/security-patterns/reference/oauth-csrf-audit.md +131 -0
- package/app/skills/skill-creator/SKILL.md +154 -0
- package/app/skills/skill-creator/templates/dashboard/index.html +130 -0
- package/app/skills/skill-creator/templates/reasoning-engine/assets/example.json +12 -0
- package/app/skills/skill-creator/templates/reasoning-engine/search.py +110 -0
- package/app/skills/subagent-development/SKILL.md +225 -0
- package/app/skills/subagent-development/reference/code-quality-reviewer-prompt.md +145 -0
- package/app/skills/subagent-development/reference/implementer-prompt.md +118 -0
- package/app/skills/subagent-development/reference/spec-reviewer-prompt.md +100 -0
- package/app/skills/swarm/SKILL.md +81 -0
- package/app/skills/swift-patterns/SKILL.md +500 -0
- package/app/skills/tdd/SKILL.md +174 -0
- package/app/skills/tdd/reference/deep-modules.md +32 -0
- package/app/skills/tdd/reference/interface-design.md +32 -0
- package/app/skills/tdd/reference/mocking.md +52 -0
- package/app/skills/tdd/reference/refactoring.md +10 -0
- package/app/skills/tdd/reference/tests.md +59 -0
- package/app/skills/teams/SKILL.md +101 -0
- package/app/skills/test/SKILL.md +107 -0
- package/app/skills/test/scripts/detect-runner.py +113 -0
- package/app/skills/testing-patterns/SKILL.md +73 -0
- package/app/skills/testing-patterns/reference/flutter-testing.md +33 -0
- package/app/skills/testing-patterns/reference/go-testing.md +52 -0
- package/app/skills/testing-patterns/reference/php-phpunit.md +39 -0
- package/app/skills/testing-patterns/reference/python-pytest.md +228 -0
- package/app/skills/testing-patterns/reference/typescript-vitest.md +50 -0
- package/app/skills/triage-issue/SKILL.md +120 -0
- package/app/skills/typescript-patterns/SKILL.md +256 -0
- package/app/skills/ubiquitous-language/SKILL.md +74 -0
- package/app/skills/verification-before-completion/SKILL.md +108 -0
- package/app/skills/workflow/SKILL.md +250 -0
- package/app/skills/write-a-prd/SKILL.md +129 -0
- package/app/skills/write-a-prd/reference/visual-companion.md +78 -0
- package/app/skills/write-a-prd/scripts/frame-template.html +111 -0
- package/app/skills/write-a-prd/scripts/visual-server.cjs +79 -0
- package/app/templates/skill/generator/SKILL.md.template +40 -0
- package/app/templates/skill/knowledge/SKILL.md.template +52 -0
- package/app/templates/skill/linter/SKILL.md.template +34 -0
- package/app/templates/skill/reviewer/SKILL.md.template +51 -0
- package/app/templates/skill/workflow/SKILL.md.template +49 -0
- package/benchmarks/README.md +111 -0
- package/benchmarks/ecosystem-dashboard.json +148 -0
- package/benchmarks/ecosystem-harvest.json +148 -0
- package/benchmarks/results.json +38 -0
- package/benchmarks/run.py +351 -0
- package/bin/ai-toolkit.js +345 -0
- package/kb/best-practices/README.md +11 -0
- package/kb/howto/README.md +11 -0
- package/kb/procedures/maintenance-sop.md +306 -0
- package/kb/reference/agents-catalog.md +124 -0
- package/kb/reference/anti-pattern-registry-format.md +221 -0
- package/kb/reference/architecture-overview.md +232 -0
- package/kb/reference/benchmark-config.md +62 -0
- package/kb/reference/ci-integration.md +66 -0
- package/kb/reference/claude-ecosystem-benchmark-snapshot.md +80 -0
- package/kb/reference/claude-ecosystem-expansion-foundations.md +102 -0
- package/kb/reference/commands-catalog.md +21 -0
- package/kb/reference/distribution-model.md +63 -0
- package/kb/reference/global-install-model.md +56 -0
- package/kb/reference/hierarchical-override-pattern.md +200 -0
- package/kb/reference/hooks-catalog.md +306 -0
- package/kb/reference/integrations.md +88 -0
- package/kb/reference/language-packs.md +52 -0
- package/kb/reference/merge-friendly-install-model.md +58 -0
- package/kb/reference/plugin-pack-conventions.md +151 -0
- package/kb/reference/quick-wins-implementation-summary.md +70 -0
- package/kb/reference/skill-templates.md +50 -0
- package/kb/reference/skills-catalog.md +215 -0
- package/kb/reference/skills-unification.md +57 -0
- package/kb/reference/stats.md +69 -0
- package/kb/reference/sync.md +76 -0
- package/kb/troubleshooting/README.md +11 -0
- package/llms-full.txt +3068 -0
- package/llms.txt +39 -0
- package/package.json +75 -0
- package/scripts/_common.py +160 -0
- package/scripts/add_rule.py +50 -0
- package/scripts/benchmark_config.py +127 -0
- package/scripts/benchmark_ecosystem.py +288 -0
- package/scripts/check_deps.py +260 -0
- package/scripts/create_skill.py +118 -0
- package/scripts/doctor.py +504 -0
- package/scripts/eject.py +113 -0
- package/scripts/emission.py +256 -0
- package/scripts/evaluate_skills.py +260 -0
- package/scripts/frontmatter.py +58 -0
- package/scripts/generate_agents_md.py +91 -0
- package/scripts/generate_aider_conf.py +51 -0
- package/scripts/generate_cline.py +35 -0
- package/scripts/generate_copilot.py +30 -0
- package/scripts/generate_cursor_rules.py +35 -0
- package/scripts/generate_gemini.py +28 -0
- package/scripts/generate_llms_txt.py +164 -0
- package/scripts/generate_roo_modes.py +80 -0
- package/scripts/generate_windsurf.py +35 -0
- package/scripts/generator_base.py +140 -0
- package/scripts/harvest_ecosystem.py +50 -0
- package/scripts/inject_rule_cli.py +101 -0
- package/scripts/inject_section_cli.py +47 -0
- package/scripts/injection.py +180 -0
- package/scripts/install.py +236 -0
- package/scripts/install_git_hooks.py +71 -0
- package/scripts/install_steps/__init__.py +5 -0
- package/scripts/install_steps/ai_tools.py +261 -0
- package/scripts/install_steps/hooks.py +90 -0
- package/scripts/install_steps/markers.py +79 -0
- package/scripts/install_steps/symlinks.py +87 -0
- package/scripts/merge-hooks.py +192 -0
- package/scripts/plugin.py +642 -0
- package/scripts/plugin_schema.py +138 -0
- package/scripts/remove_rule.py +58 -0
- package/scripts/stats.py +81 -0
- package/scripts/sync.py +215 -0
- package/scripts/uninstall.py +292 -0
- package/scripts/validate.py +700 -0
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: rust-patterns
|
|
3
|
+
description: "Loaded when user asks about Rust development patterns"
|
|
4
|
+
effort: medium
|
|
5
|
+
user-invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Rust Patterns
|
|
9
|
+
|
|
10
|
+
## Project Structure
|
|
11
|
+
|
|
12
|
+
```
|
|
13
|
+
my-app/
|
|
14
|
+
├── Cargo.toml
|
|
15
|
+
├── src/
|
|
16
|
+
│ ├── main.rs # Binary entry point
|
|
17
|
+
│ ├── lib.rs # Library root (re-exports)
|
|
18
|
+
│ ├── error.rs # Crate-level error types
|
|
19
|
+
│ ├── api/
|
|
20
|
+
│ │ ├── mod.rs
|
|
21
|
+
│ │ └── handlers.rs
|
|
22
|
+
│ └── domain/
|
|
23
|
+
│ ├── mod.rs
|
|
24
|
+
│ └── service.rs
|
|
25
|
+
├── tests/ # Integration tests (separate crate)
|
|
26
|
+
│ └── api_test.rs
|
|
27
|
+
├── benches/ # criterion benchmarks
|
|
28
|
+
│ └── throughput.rs
|
|
29
|
+
└── examples/
|
|
30
|
+
└── demo.rs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Workspace layout for multi-crate projects:
|
|
34
|
+
|
|
35
|
+
```toml
|
|
36
|
+
# Cargo.toml (workspace root)
|
|
37
|
+
[workspace]
|
|
38
|
+
resolver = "2"
|
|
39
|
+
members = ["crates/core", "crates/api", "crates/cli"]
|
|
40
|
+
|
|
41
|
+
[workspace.dependencies]
|
|
42
|
+
serde = { version = "1", features = ["derive"] }
|
|
43
|
+
tokio = { version = "1", features = ["full"] }
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## Idioms / Code Style
|
|
49
|
+
|
|
50
|
+
### Ownership and Borrowing
|
|
51
|
+
|
|
52
|
+
```rust
|
|
53
|
+
// Borrow when you only need to read
|
|
54
|
+
fn print_name(name: &str) { println!("{name}"); }
|
|
55
|
+
|
|
56
|
+
// Take ownership when storing or consuming the value
|
|
57
|
+
fn register_user(name: String) -> User {
|
|
58
|
+
User { name, id: Uuid::new_v4() }
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Lifetimes
|
|
63
|
+
|
|
64
|
+
```rust
|
|
65
|
+
// Annotate only when the compiler cannot infer
|
|
66
|
+
struct Parser<'input> {
|
|
67
|
+
source: &'input str,
|
|
68
|
+
pos: usize,
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
impl<'input> Parser<'input> {
|
|
72
|
+
fn next_token(&mut self) -> Option<&'input str> {
|
|
73
|
+
let start = self.pos;
|
|
74
|
+
// ... advance self.pos ...
|
|
75
|
+
Some(&self.source[start..self.pos])
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
### Trait-Based Design
|
|
81
|
+
|
|
82
|
+
```rust
|
|
83
|
+
trait Repository {
|
|
84
|
+
fn find_by_id(&self, id: Uuid) -> Result<Option<User>, DbError>;
|
|
85
|
+
fn save(&self, user: &User) -> Result<(), DbError>;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Accept generics for testability
|
|
89
|
+
fn create_user(repo: &impl Repository, name: String) -> Result<User, AppError> {
|
|
90
|
+
let user = User::new(name);
|
|
91
|
+
repo.save(&user)?;
|
|
92
|
+
Ok(user)
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Iterators, Pattern Matching, Newtype
|
|
97
|
+
|
|
98
|
+
```rust
|
|
99
|
+
// Iterator chains over manual loops
|
|
100
|
+
let active: Vec<&str> = users.iter()
|
|
101
|
+
.filter(|u| u.is_active)
|
|
102
|
+
.map(|u| u.email.as_str())
|
|
103
|
+
.collect();
|
|
104
|
+
|
|
105
|
+
// Exhaustive matching
|
|
106
|
+
match command {
|
|
107
|
+
Command::Start { port } => start_server(port),
|
|
108
|
+
Command::Stop => shutdown(),
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// let-else for early exit (Rust 1.65+)
|
|
112
|
+
let Some(cfg) = load_config() else { return Ok(Config::default()); };
|
|
113
|
+
|
|
114
|
+
// Newtype to prevent primitive misuse
|
|
115
|
+
struct UserId(Uuid);
|
|
116
|
+
struct Email(String);
|
|
117
|
+
|
|
118
|
+
impl Email {
|
|
119
|
+
fn new(raw: &str) -> Result<Self, ValidationError> {
|
|
120
|
+
if raw.contains('@') { Ok(Self(raw.to_lowercase())) }
|
|
121
|
+
else { Err(ValidationError::InvalidEmail) }
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Builder Pattern
|
|
127
|
+
|
|
128
|
+
```rust
|
|
129
|
+
#[derive(Default)]
|
|
130
|
+
struct RequestBuilder { url: String, timeout: Option<Duration> }
|
|
131
|
+
|
|
132
|
+
impl RequestBuilder {
|
|
133
|
+
fn url(mut self, url: impl Into<String>) -> Self { self.url = url.into(); self }
|
|
134
|
+
fn timeout(mut self, d: Duration) -> Self { self.timeout = Some(d); self }
|
|
135
|
+
fn build(self) -> Result<Request, BuildError> {
|
|
136
|
+
if self.url.is_empty() { return Err(BuildError::MissingUrl); }
|
|
137
|
+
Ok(Request { url: self.url, timeout: self.timeout.unwrap_or(Duration::from_secs(30)) })
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
---
|
|
143
|
+
|
|
144
|
+
## Error Handling
|
|
145
|
+
|
|
146
|
+
### thiserror (libraries) vs anyhow (binaries)
|
|
147
|
+
|
|
148
|
+
```rust
|
|
149
|
+
use thiserror::Error;
|
|
150
|
+
|
|
151
|
+
#[derive(Debug, Error)]
|
|
152
|
+
pub enum AppError {
|
|
153
|
+
#[error("not found: {0}")]
|
|
154
|
+
NotFound(String),
|
|
155
|
+
#[error("validation failed: {0}")]
|
|
156
|
+
Validation(String),
|
|
157
|
+
#[error("database error")]
|
|
158
|
+
Database(#[from] sqlx::Error),
|
|
159
|
+
#[error(transparent)]
|
|
160
|
+
Unexpected(#[from] anyhow::Error),
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```rust
|
|
165
|
+
// anyhow for application / binary code -- adds context to any error
|
|
166
|
+
use anyhow::{Context, Result};
|
|
167
|
+
|
|
168
|
+
fn load_config(path: &Path) -> Result<Config> {
|
|
169
|
+
let content = fs::read_to_string(path)
|
|
170
|
+
.with_context(|| format!("failed to read {}", path.display()))?;
|
|
171
|
+
toml::from_str(&content).context("invalid TOML")
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Error Propagation and Boundary Mapping
|
|
176
|
+
|
|
177
|
+
```rust
|
|
178
|
+
// ? converts and propagates via From impls
|
|
179
|
+
fn get_email(pool: &PgPool, id: Uuid) -> Result<String, AppError> {
|
|
180
|
+
let user = sqlx::query_as!(User, "SELECT * FROM users WHERE id = $1", id)
|
|
181
|
+
.fetch_optional(pool).await?
|
|
182
|
+
.ok_or_else(|| AppError::NotFound(format!("user {id}")))?;
|
|
183
|
+
Ok(user.email)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Map domain errors to HTTP at the API boundary
|
|
187
|
+
impl IntoResponse for AppError {
|
|
188
|
+
fn into_response(self) -> axum::response::Response {
|
|
189
|
+
let (status, msg) = match &self {
|
|
190
|
+
AppError::NotFound(m) => (StatusCode::NOT_FOUND, m.clone()),
|
|
191
|
+
AppError::Validation(m) => (StatusCode::BAD_REQUEST, m.clone()),
|
|
192
|
+
_ => (StatusCode::INTERNAL_SERVER_ERROR, "internal error".into()),
|
|
193
|
+
};
|
|
194
|
+
(status, Json(json!({ "error": msg }))).into_response()
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
## Testing Patterns
|
|
202
|
+
|
|
203
|
+
### Unit Tests (inline module)
|
|
204
|
+
|
|
205
|
+
```rust
|
|
206
|
+
#[cfg(test)]
|
|
207
|
+
mod tests {
|
|
208
|
+
use super::*;
|
|
209
|
+
|
|
210
|
+
#[test]
|
|
211
|
+
fn email_rejects_invalid() { assert!(Email::new("bad").is_err()); }
|
|
212
|
+
|
|
213
|
+
#[tokio::test]
|
|
214
|
+
async fn fetches_user() {
|
|
215
|
+
let pool = setup_test_db().await;
|
|
216
|
+
let user = get_user(&pool, test_id()).await.unwrap();
|
|
217
|
+
assert_eq!(user.name, "Alice");
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Integration Tests (tests/ directory)
|
|
223
|
+
|
|
224
|
+
```rust
|
|
225
|
+
// tests/api_test.rs -- compiled as separate crate, only sees pub API
|
|
226
|
+
#[tokio::test]
|
|
227
|
+
async fn health_returns_200() {
|
|
228
|
+
let app = my_app::app().await;
|
|
229
|
+
let resp = app.oneshot(
|
|
230
|
+
Request::builder().uri("/health").body(Body::empty()).unwrap()
|
|
231
|
+
).await.unwrap();
|
|
232
|
+
assert_eq!(resp.status(), StatusCode::OK);
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Mocking (mockall) and Property Testing (proptest)
|
|
237
|
+
|
|
238
|
+
```rust
|
|
239
|
+
use mockall::automock;
|
|
240
|
+
|
|
241
|
+
#[automock]
|
|
242
|
+
trait UserRepo { fn find(&self, id: Uuid) -> Result<Option<User>, DbError>; }
|
|
243
|
+
|
|
244
|
+
#[test]
|
|
245
|
+
fn returns_not_found_when_missing() {
|
|
246
|
+
let mut mock = MockUserRepo::new();
|
|
247
|
+
mock.expect_find().returning(|_| Ok(None));
|
|
248
|
+
assert!(matches!(UserService::new(mock).get_user(id), Err(AppError::NotFound(_))));
|
|
249
|
+
}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
```rust
|
|
253
|
+
use proptest::prelude::*;
|
|
254
|
+
proptest! {
|
|
255
|
+
#[test]
|
|
256
|
+
fn roundtrips(s in "[a-z]{1,20}@[a-z]{1,10}\\.[a-z]{2,4}") {
|
|
257
|
+
let e = Email::new(&s).unwrap();
|
|
258
|
+
assert_eq!(e.to_string(), s.to_lowercase());
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
cargo test # All tests
|
|
265
|
+
cargo test --lib # Unit only
|
|
266
|
+
cargo test --test api_test # Single integration file
|
|
267
|
+
cargo nextest run # Parallel runner, better output
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
---
|
|
271
|
+
|
|
272
|
+
## Common Libraries
|
|
273
|
+
|
|
274
|
+
| Crate | Purpose | Notes |
|
|
275
|
+
|-------|---------|-------|
|
|
276
|
+
| **serde** / serde_json | Serialization | `#[derive(Serialize, Deserialize)]` on DTOs |
|
|
277
|
+
| **tokio** | Async runtime | `features = ["full"]` for apps |
|
|
278
|
+
| **axum** | HTTP framework | Tower-based, extractors, `State` |
|
|
279
|
+
| **clap** | CLI parsing | `#[derive(Parser)]` |
|
|
280
|
+
| **reqwest** | HTTP client | Async, rustls TLS |
|
|
281
|
+
| **tracing** | Structured logging | Replaces `log`; use `tracing-subscriber` |
|
|
282
|
+
| **sqlx** | Async SQL | Compile-time checked queries |
|
|
283
|
+
| **tower** | Middleware | Layers, timeouts, rate limiting |
|
|
284
|
+
| **rayon** | Data parallelism | `.par_iter()` drop-in |
|
|
285
|
+
| **criterion** | Benchmarking | Statistical, HTML reports |
|
|
286
|
+
|
|
287
|
+
### Axum + Tracing Minimal Server
|
|
288
|
+
|
|
289
|
+
```rust
|
|
290
|
+
use axum::{extract::State, routing::get, Json, Router};
|
|
291
|
+
use std::sync::Arc;
|
|
292
|
+
|
|
293
|
+
struct AppState { db: PgPool }
|
|
294
|
+
|
|
295
|
+
async fn list_users(State(s): State<Arc<AppState>>) -> Json<Vec<User>> {
|
|
296
|
+
Json(sqlx::query_as!(User, "SELECT * FROM users")
|
|
297
|
+
.fetch_all(&s.db).await.unwrap())
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#[tokio::main]
|
|
301
|
+
async fn main() {
|
|
302
|
+
tracing_subscriber::fmt()
|
|
303
|
+
.with_env_filter(tracing_subscriber::EnvFilter::from_default_env())
|
|
304
|
+
.json().init();
|
|
305
|
+
let pool = PgPool::connect(&std::env::var("DATABASE_URL").unwrap()).await.unwrap();
|
|
306
|
+
let app = Router::new().route("/users", get(list_users)).with_state(Arc::new(AppState { db: pool }));
|
|
307
|
+
let listener = tokio::net::TcpListener::bind("0.0.0.0:3000").await.unwrap();
|
|
308
|
+
axum::serve(listener, app).await.unwrap();
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
## Performance Tips
|
|
315
|
+
|
|
316
|
+
```rust
|
|
317
|
+
// Avoid cloning -- return references when possible
|
|
318
|
+
fn names(data: &[Record]) -> Vec<&str> {
|
|
319
|
+
data.iter().map(|r| r.name.as_str()).collect()
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// Cow for conditional ownership -- zero alloc on the happy path
|
|
323
|
+
use std::borrow::Cow;
|
|
324
|
+
fn normalize(input: &str) -> Cow<'_, str> {
|
|
325
|
+
if input.contains(' ') { Cow::Owned(input.replace(' ', "_")) }
|
|
326
|
+
else { Cow::Borrowed(input) }
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Rayon for CPU-bound parallelism
|
|
330
|
+
use rayon::prelude::*;
|
|
331
|
+
let out: Vec<_> = inputs.par_iter().map(|i| compute(i)).collect();
|
|
332
|
+
|
|
333
|
+
// Preallocate collections
|
|
334
|
+
let mut v = Vec::with_capacity(items.len());
|
|
335
|
+
|
|
336
|
+
// Zero-cost abstractions: iterators compile to the same code as manual loops
|
|
337
|
+
let sum: u64 = values.iter().filter(|v| **v > 0).sum();
|
|
338
|
+
|
|
339
|
+
// #[inline] only on small hot functions crossing crate boundaries
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
### Benchmarking (criterion)
|
|
343
|
+
|
|
344
|
+
```rust
|
|
345
|
+
use criterion::{black_box, criterion_group, criterion_main, Criterion};
|
|
346
|
+
|
|
347
|
+
fn bench_parse(c: &mut Criterion) {
|
|
348
|
+
let input = include_str!("../fixtures/large.json");
|
|
349
|
+
c.bench_function("parse_json", |b| b.iter(|| parse(black_box(input))));
|
|
350
|
+
}
|
|
351
|
+
criterion_group!(benches, bench_parse);
|
|
352
|
+
criterion_main!(benches);
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Build / Package Management
|
|
358
|
+
|
|
359
|
+
### Cargo.toml
|
|
360
|
+
|
|
361
|
+
```toml
|
|
362
|
+
[package]
|
|
363
|
+
name = "my-app"
|
|
364
|
+
version = "0.1.0"
|
|
365
|
+
edition = "2021"
|
|
366
|
+
rust-version = "1.75" # MSRV
|
|
367
|
+
|
|
368
|
+
[dependencies]
|
|
369
|
+
serde = { version = "1", features = ["derive"] }
|
|
370
|
+
tokio = { version = "1", features = ["full"] }
|
|
371
|
+
|
|
372
|
+
[dev-dependencies]
|
|
373
|
+
criterion = { version = "0.5", features = ["html_reports"] }
|
|
374
|
+
mockall = "0.13"
|
|
375
|
+
|
|
376
|
+
[[bench]]
|
|
377
|
+
name = "throughput"
|
|
378
|
+
harness = false
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
### Feature Flags
|
|
382
|
+
|
|
383
|
+
```toml
|
|
384
|
+
[features]
|
|
385
|
+
default = ["json"]
|
|
386
|
+
json = ["serde_json"]
|
|
387
|
+
postgres = ["sqlx/postgres"]
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
```rust
|
|
391
|
+
#[cfg(feature = "postgres")]
|
|
392
|
+
pub mod pg_backend;
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
### Release Profile
|
|
396
|
+
|
|
397
|
+
```toml
|
|
398
|
+
[profile.release]
|
|
399
|
+
lto = true
|
|
400
|
+
codegen-units = 1
|
|
401
|
+
strip = true
|
|
402
|
+
panic = "abort"
|
|
403
|
+
|
|
404
|
+
[profile.dev.package."*"]
|
|
405
|
+
opt-level = 2 # Optimize deps even in dev
|
|
406
|
+
```
|
|
407
|
+
|
|
408
|
+
### Cross-Compilation
|
|
409
|
+
|
|
410
|
+
```bash
|
|
411
|
+
rustup target add x86_64-unknown-linux-musl
|
|
412
|
+
cargo build --release --target x86_64-unknown-linux-musl
|
|
413
|
+
# Or use cross for Docker-based builds
|
|
414
|
+
cargo install cross && cross build --release --target aarch64-unknown-linux-gnu
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
### Essential Cargo Commands
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
cargo clippy -- -D warnings # Lint (treat warnings as errors)
|
|
421
|
+
cargo fmt --check # Format check
|
|
422
|
+
cargo doc --open # Generate docs
|
|
423
|
+
cargo tree -d # Duplicate dependencies
|
|
424
|
+
cargo audit # Known vulnerabilities
|
|
425
|
+
cargo deny check # License and advisory
|
|
426
|
+
cargo bloat --release # Binary size analysis
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
### CI Pipeline (minimum)
|
|
430
|
+
|
|
431
|
+
```bash
|
|
432
|
+
cargo fmt --check && cargo clippy -- -D warnings && cargo test && cargo audit
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
---
|
|
436
|
+
|
|
437
|
+
## Anti-Patterns
|
|
438
|
+
|
|
439
|
+
| Anti-Pattern | Problem | Fix |
|
|
440
|
+
|--------------|---------|-----|
|
|
441
|
+
| `.unwrap()` in lib code | Panics | Return `Result`/`Option` |
|
|
442
|
+
| `.clone()` everywhere | Hidden allocs | Borrow, `Cow`, restructure ownership |
|
|
443
|
+
| `String` in every field | Unnecessary allocs | `&str` or `Cow<str>` where lifetime allows |
|
|
444
|
+
| `Box<dyn Error>` only | No matching | `thiserror` enums |
|
|
445
|
+
| `Arc<Mutex<T>>` first | Contention | Channels (`tokio::sync::mpsc`) or actors |
|
|
446
|
+
| Ignoring `#[must_use]` | Silent drops | Handle or `let _ =` explicitly |
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: search
|
|
3
|
+
description: "Search the knowledge base with semantic and hybrid modes"
|
|
4
|
+
user-invocable: true
|
|
5
|
+
effort: medium
|
|
6
|
+
argument-hint: "[query]"
|
|
7
|
+
allowed-tools: Read, Grep, Glob
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Knowledge Base Search
|
|
11
|
+
|
|
12
|
+
$ARGUMENTS
|
|
13
|
+
|
|
14
|
+
## Search Methods
|
|
15
|
+
|
|
16
|
+
### Method 1: MCP Tools (requires rag-mcp MCP server)
|
|
17
|
+
|
|
18
|
+
If the `rag-mcp` MCP server is configured, use these tools:
|
|
19
|
+
|
|
20
|
+
| Tool | Best For | Speed |
|
|
21
|
+
|------|----------|-------|
|
|
22
|
+
| `smart_query` | Default (90% of queries), auto-routing | 2-4s |
|
|
23
|
+
| `hybrid_search_kb` | Raw vector + text search | <1s |
|
|
24
|
+
| `get_document` | Full document content | <1s |
|
|
25
|
+
| `crag_search` | Vague queries (Corrective RAG) | 1-3s |
|
|
26
|
+
| `multi_hop_search` | Complex multi-step reasoning | 20-30s |
|
|
27
|
+
|
|
28
|
+
```python
|
|
29
|
+
# Primary search
|
|
30
|
+
smart_query("your search query", limit=10)
|
|
31
|
+
|
|
32
|
+
# Full document retrieval
|
|
33
|
+
get_document(path="kb/reference/architecture.md")
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Method 2: Local File Search (fallback, always available)
|
|
37
|
+
|
|
38
|
+
If MCP tools are unavailable, use built-in tools:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
# Search file contents
|
|
42
|
+
Grep: pattern="your query" path="kb/"
|
|
43
|
+
|
|
44
|
+
# Search file names
|
|
45
|
+
Glob: pattern="kb/**/*.md"
|
|
46
|
+
|
|
47
|
+
# Read specific document
|
|
48
|
+
Read: "kb/reference/architecture.md"
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Search Tips
|
|
52
|
+
|
|
53
|
+
1. **Be specific** - "nginx rate limiting" > "rate limiting"
|
|
54
|
+
2. **Try MCP first**, fall back to Grep/Glob if unavailable
|
|
55
|
+
3. **Use multi-hop** for "compare X with Y" questions (MCP only)
|
|
56
|
+
4. **Always cite sources**: `[PATH: kb/reference/doc.md]`
|
|
57
|
+
|
|
58
|
+
## Examples
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
/search rate limiting configuration
|
|
62
|
+
/search how to deploy to production
|
|
63
|
+
/search database migration patterns
|
|
64
|
+
```
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-patterns
|
|
3
|
+
description: "Loaded when user asks about security, OWASP, or auth patterns"
|
|
4
|
+
effort: medium
|
|
5
|
+
user-invocable: false
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Security Patterns Skill
|
|
9
|
+
|
|
10
|
+
## OWASP Top 10 Prevention
|
|
11
|
+
|
|
12
|
+
| Risk | Prevention |
|
|
13
|
+
|------|------------|
|
|
14
|
+
| Injection | Parameterized queries, ORM |
|
|
15
|
+
| Broken Auth | MFA, secure sessions |
|
|
16
|
+
| Sensitive Data | Encryption, HTTPS |
|
|
17
|
+
| XXE | Disable external entities |
|
|
18
|
+
| Broken Access | RBAC, resource validation |
|
|
19
|
+
| Security Misconfig | Security headers, defaults |
|
|
20
|
+
| XSS | Escaping, CSP |
|
|
21
|
+
| Insecure Deserialization | Signed tokens, validation |
|
|
22
|
+
| Vulnerable Components | Dependency scanning |
|
|
23
|
+
| Insufficient Logging | Audit logs, monitoring |
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Security Headers
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
# FastAPI middleware
|
|
31
|
+
@app.middleware("http")
|
|
32
|
+
async def security_headers(request, call_next):
|
|
33
|
+
response = await call_next(request)
|
|
34
|
+
response.headers["X-Content-Type-Options"] = "nosniff"
|
|
35
|
+
response.headers["X-Frame-Options"] = "DENY"
|
|
36
|
+
response.headers["X-XSS-Protection"] = "1; mode=block"
|
|
37
|
+
response.headers["Strict-Transport-Security"] = "max-age=31536000; includeSubDomains"
|
|
38
|
+
response.headers["Content-Security-Policy"] = "default-src 'self'"
|
|
39
|
+
return response
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Secrets Management
|
|
45
|
+
|
|
46
|
+
### Environment Variables
|
|
47
|
+
```bash
|
|
48
|
+
# .env (never commit)
|
|
49
|
+
DATABASE_URL=postgresql://...
|
|
50
|
+
API_SECRET=...
|
|
51
|
+
|
|
52
|
+
# .env.example (commit this)
|
|
53
|
+
DATABASE_URL=postgresql://user:pass@localhost/db
|
|
54
|
+
API_SECRET=your-secret-here
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Secret Scanning
|
|
58
|
+
```yaml
|
|
59
|
+
# pre-commit hook
|
|
60
|
+
- repo: https://github.com/Yelp/detect-secrets
|
|
61
|
+
hooks:
|
|
62
|
+
- id: detect-secrets
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
---
|
|
66
|
+
|
|
67
|
+
## Rate Limiting
|
|
68
|
+
|
|
69
|
+
```python
|
|
70
|
+
from slowapi import Limiter
|
|
71
|
+
from slowapi.util import get_remote_address
|
|
72
|
+
|
|
73
|
+
limiter = Limiter(key_func=get_remote_address)
|
|
74
|
+
|
|
75
|
+
@app.get("/api/resource")
|
|
76
|
+
@limiter.limit("100/minute")
|
|
77
|
+
async def resource():
|
|
78
|
+
pass
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Reference Guides
|
|
84
|
+
|
|
85
|
+
For authentication patterns (JWT, passwords, token strategy), see [reference/authentication.md](reference/authentication.md).
|
|
86
|
+
|
|
87
|
+
For authorization patterns (RBAC, ABAC), see [reference/authorization.md](reference/authorization.md).
|
|
88
|
+
|
|
89
|
+
For input validation patterns (SQL injection, XSS, Pydantic), see [reference/input-validation.md](reference/input-validation.md).
|
|
90
|
+
|
|
91
|
+
For OAuth2 flows, CSRF protection, and audit logging, see [reference/oauth-csrf-audit.md](reference/oauth-csrf-audit.md).
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# Authentication Patterns
|
|
2
|
+
|
|
3
|
+
## JWT Structure
|
|
4
|
+
```
|
|
5
|
+
Header.Payload.Signature
|
|
6
|
+
|
|
7
|
+
{
|
|
8
|
+
"alg": "HS256",
|
|
9
|
+
"typ": "JWT"
|
|
10
|
+
}
|
|
11
|
+
.
|
|
12
|
+
{
|
|
13
|
+
"sub": "user_id",
|
|
14
|
+
"exp": 1234567890,
|
|
15
|
+
"iat": 1234567800
|
|
16
|
+
}
|
|
17
|
+
.
|
|
18
|
+
[signature]
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Token Strategy
|
|
22
|
+
| Token Type | Storage | Lifetime |
|
|
23
|
+
|------------|---------|----------|
|
|
24
|
+
| Access Token | Memory | 15 min |
|
|
25
|
+
| Refresh Token | HttpOnly Cookie | 7 days |
|
|
26
|
+
| API Key | Secure storage | Long-lived |
|
|
27
|
+
|
|
28
|
+
## Password Hashing
|
|
29
|
+
```python
|
|
30
|
+
# Python (bcrypt)
|
|
31
|
+
import bcrypt
|
|
32
|
+
hashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(12))
|
|
33
|
+
|
|
34
|
+
# Node.js (argon2)
|
|
35
|
+
import argon2 from 'argon2';
|
|
36
|
+
const hash = await argon2.hash(password);
|
|
37
|
+
```
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# Authorization Patterns
|
|
2
|
+
|
|
3
|
+
## RBAC (Role-Based)
|
|
4
|
+
```python
|
|
5
|
+
ROLES = {
|
|
6
|
+
"admin": ["read", "write", "delete", "admin"],
|
|
7
|
+
"editor": ["read", "write"],
|
|
8
|
+
"viewer": ["read"]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
def check_permission(user, action):
|
|
12
|
+
return action in ROLES.get(user.role, [])
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## ABAC (Attribute-Based)
|
|
16
|
+
```python
|
|
17
|
+
def can_access(user, resource):
|
|
18
|
+
return (
|
|
19
|
+
user.department == resource.department
|
|
20
|
+
and user.clearance >= resource.classification
|
|
21
|
+
)
|
|
22
|
+
```
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Input Validation
|
|
2
|
+
|
|
3
|
+
## Validation Rules
|
|
4
|
+
```python
|
|
5
|
+
from pydantic import BaseModel, EmailStr, constr
|
|
6
|
+
|
|
7
|
+
class UserInput(BaseModel):
|
|
8
|
+
email: EmailStr
|
|
9
|
+
username: constr(min_length=3, max_length=20, pattern=r'^[a-zA-Z0-9_]+$')
|
|
10
|
+
age: int = Field(ge=0, le=150)
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## SQL Injection Prevention
|
|
14
|
+
```python
|
|
15
|
+
# Bad
|
|
16
|
+
query = f"SELECT * FROM users WHERE email = '{email}'"
|
|
17
|
+
|
|
18
|
+
# Good (parameterized)
|
|
19
|
+
cursor.execute("SELECT * FROM users WHERE email = %s", (email,))
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## XSS Prevention
|
|
23
|
+
```python
|
|
24
|
+
# Escape HTML
|
|
25
|
+
from markupsafe import escape
|
|
26
|
+
safe_text = escape(user_input)
|
|
27
|
+
|
|
28
|
+
# Content Security Policy
|
|
29
|
+
response.headers['Content-Security-Policy'] = "default-src 'self'"
|
|
30
|
+
```
|