@coralai/sps-cli 0.41.2 → 0.43.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/README.md +34 -3
- package/dist/commands/cardAdd.d.ts +1 -1
- package/dist/commands/cardAdd.d.ts.map +1 -1
- package/dist/commands/cardAdd.js +16 -6
- package/dist/commands/cardAdd.js.map +1 -1
- package/dist/commands/cardDashboard.js +1 -1
- package/dist/commands/cardDashboard.js.map +1 -1
- package/dist/commands/doctor.d.ts +9 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +3 -314
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/hookCommand.d.ts.map +1 -1
- package/dist/commands/hookCommand.js +6 -7
- package/dist/commands/hookCommand.js.map +1 -1
- package/dist/commands/pmCommand.js +1 -1
- package/dist/commands/pmCommand.js.map +1 -1
- package/dist/commands/projectInit.d.ts.map +1 -1
- package/dist/commands/projectInit.js +60 -37
- package/dist/commands/projectInit.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +3 -30
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/skillCommand.d.ts +2 -0
- package/dist/commands/skillCommand.d.ts.map +1 -0
- package/dist/commands/skillCommand.js +235 -0
- package/dist/commands/skillCommand.js.map +1 -0
- package/dist/commands/tick.js +1 -1
- package/dist/commands/tick.js.map +1 -1
- package/dist/core/checklist.d.ts +22 -0
- package/dist/core/checklist.d.ts.map +1 -0
- package/dist/core/checklist.js +38 -0
- package/dist/core/checklist.js.map +1 -0
- package/dist/core/checklist.test.d.ts +2 -0
- package/dist/core/checklist.test.d.ts.map +1 -0
- package/dist/core/checklist.test.js +74 -0
- package/dist/core/checklist.test.js.map +1 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/config.test.js +7 -4
- package/dist/core/config.test.js.map +1 -1
- package/dist/core/context.d.ts +1 -1
- package/dist/core/context.d.ts.map +1 -1
- package/dist/core/skillStore.d.ts +46 -0
- package/dist/core/skillStore.d.ts.map +1 -0
- package/dist/core/skillStore.js +197 -0
- package/dist/core/skillStore.js.map +1 -0
- package/dist/core/skillStore.test.d.ts +2 -0
- package/dist/core/skillStore.test.d.ts.map +1 -0
- package/dist/core/skillStore.test.js +190 -0
- package/dist/core/skillStore.test.js.map +1 -0
- package/dist/engines/EventHandler.test.js +3 -3
- package/dist/engines/EventHandler.test.js.map +1 -1
- package/dist/engines/MonitorEngine.js +2 -2
- package/dist/engines/MonitorEngine.js.map +1 -1
- package/dist/engines/SchedulerEngine.js +1 -1
- package/dist/engines/SchedulerEngine.js.map +1 -1
- package/dist/engines/StageEngine.js +3 -3
- package/dist/engines/StageEngine.js.map +1 -1
- package/dist/engines/engine-pipeline-adapter.test.js +2 -2
- package/dist/engines/engine-pipeline-adapter.test.js.map +1 -1
- package/dist/interfaces/TaskBackend.d.ts +3 -1
- package/dist/interfaces/TaskBackend.d.ts.map +1 -1
- package/dist/main.js +19 -17
- package/dist/main.js.map +1 -1
- package/dist/models/types.d.ts +16 -1
- package/dist/models/types.d.ts.map +1 -1
- package/dist/providers/MarkdownTaskBackend.d.ts +2 -1
- package/dist/providers/MarkdownTaskBackend.d.ts.map +1 -1
- package/dist/providers/MarkdownTaskBackend.js +28 -5
- package/dist/providers/MarkdownTaskBackend.js.map +1 -1
- package/dist/providers/registry.d.ts.map +1 -1
- package/dist/providers/registry.js +5 -7
- package/dist/providers/registry.js.map +1 -1
- package/package.json +1 -1
- package/project-template/.claude/hooks/start.sh +44 -0
- package/project-template/.claude/settings.json +1 -1
- package/skills/architecture-decision-records/SKILL.md +207 -0
- package/skills/backend/SKILL.md +62 -0
- package/skills/backend/references/api-design.md +168 -0
- package/skills/backend/references/caching.md +181 -0
- package/skills/backend/references/data-access.md +173 -0
- package/skills/backend/references/layering.md +181 -0
- package/skills/backend/references/observability.md +190 -0
- package/skills/backend/references/resilience.md +201 -0
- package/skills/backend/references/security.md +186 -0
- package/skills/backend-architect/SKILL.md +119 -0
- package/skills/code-reviewer/SKILL.md +143 -0
- package/skills/coding-standards/SKILL.md +60 -0
- package/skills/coding-standards/references/clean-code.md +258 -0
- package/skills/coding-standards/references/code-review.md +192 -0
- package/skills/coding-standards/references/commits-and-prs.md +226 -0
- package/skills/coding-standards/references/error-strategy.md +193 -0
- package/skills/coding-standards/references/naming.md +185 -0
- package/skills/coding-standards/references/tdd.md +171 -0
- package/skills/database/SKILL.md +53 -0
- package/skills/database/references/indexing.md +190 -0
- package/skills/database/references/migrations.md +199 -0
- package/skills/database/references/nosql.md +185 -0
- package/skills/database/references/queries.md +295 -0
- package/skills/database/references/scaling.md +203 -0
- package/skills/database/references/schema.md +191 -0
- package/skills/database-optimizer/SKILL.md +168 -0
- package/skills/debugging-workflow/SKILL.md +244 -0
- package/skills/devops/SKILL.md +55 -0
- package/skills/devops/references/ci-cd.md +204 -0
- package/skills/devops/references/containers.md +272 -0
- package/skills/devops/references/deploy.md +201 -0
- package/skills/devops/references/iac.md +252 -0
- package/skills/devops/references/observability.md +228 -0
- package/skills/devops/references/secrets.md +178 -0
- package/skills/devops-automator/SKILL.md +164 -0
- package/skills/frontend/SKILL.md +52 -0
- package/skills/frontend/references/accessibility.md +222 -0
- package/skills/frontend/references/components.md +206 -0
- package/skills/frontend/references/performance.md +219 -0
- package/skills/frontend/references/routing.md +209 -0
- package/skills/frontend/references/state.md +190 -0
- package/skills/frontend/references/testing.md +216 -0
- package/skills/frontend-developer/SKILL.md +115 -0
- package/skills/git-workflow/SKILL.md +355 -0
- package/skills/golang/SKILL.md +49 -0
- package/skills/golang/references/concurrency.md +284 -0
- package/skills/golang/references/errors.md +241 -0
- package/skills/golang/references/idioms.md +285 -0
- package/skills/golang/references/testing.md +238 -0
- package/skills/java/SKILL.md +50 -0
- package/skills/java/references/concurrency.md +194 -0
- package/skills/java/references/idioms.md +283 -0
- package/skills/java/references/testing.md +228 -0
- package/skills/kotlin/SKILL.md +47 -0
- package/skills/kotlin/references/coroutines.md +240 -0
- package/skills/kotlin/references/idioms.md +268 -0
- package/skills/kotlin/references/testing.md +219 -0
- package/skills/mobile/SKILL.md +50 -0
- package/skills/mobile/references/architecture.md +204 -0
- package/skills/mobile/references/navigation.md +158 -0
- package/skills/mobile/references/performance.md +152 -0
- package/skills/mobile/references/platform.md +166 -0
- package/skills/mobile/references/state-and-data.md +174 -0
- package/skills/python/SKILL.md +51 -0
- package/skills/python/THIRD_PARTY.md +14 -0
- package/skills/python/references/async.md +218 -0
- package/skills/python/references/error-handling.md +254 -0
- package/skills/python/references/idioms.md +279 -0
- package/skills/python/references/packaging.md +233 -0
- package/skills/python/references/testing.md +269 -0
- package/skills/python/references/typing.md +292 -0
- package/skills/qa-tester/SKILL.md +186 -0
- package/skills/rust/SKILL.md +50 -0
- package/skills/rust/references/async.md +224 -0
- package/skills/rust/references/errors.md +240 -0
- package/skills/rust/references/ownership.md +263 -0
- package/skills/rust/references/testing.md +274 -0
- package/skills/rust/references/traits.md +250 -0
- package/skills/security-engineer/SKILL.md +157 -0
- package/skills/swift/SKILL.md +48 -0
- package/skills/swift/references/concurrency.md +280 -0
- package/skills/swift/references/idioms.md +334 -0
- package/skills/swift/references/testing.md +229 -0
- package/skills/typescript/SKILL.md +51 -0
- package/skills/typescript/references/async.md +241 -0
- package/skills/typescript/references/errors.md +208 -0
- package/skills/typescript/references/idioms.md +246 -0
- package/skills/typescript/references/testing.md +225 -0
- package/skills/typescript/references/tooling.md +208 -0
- package/skills/typescript/references/types.md +259 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
# Rust — Traits
|
|
2
|
+
|
|
3
|
+
Traits, generics, `impl Trait`, associated types, trait objects.
|
|
4
|
+
|
|
5
|
+
## What a trait is
|
|
6
|
+
|
|
7
|
+
A trait is a set of methods a type implements. Like interfaces in Go / Java, but:
|
|
8
|
+
- You can add a trait impl for a type you don't own (with orphan rule limits).
|
|
9
|
+
- Traits can have default methods.
|
|
10
|
+
- Generic bounds + associated types make them more expressive than Java interfaces.
|
|
11
|
+
|
|
12
|
+
```rust
|
|
13
|
+
pub trait Store {
|
|
14
|
+
fn get(&self, k: &str) -> Option<String>;
|
|
15
|
+
fn put(&mut self, k: &str, v: &str);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
pub struct MemStore { data: HashMap<String, String> }
|
|
19
|
+
|
|
20
|
+
impl Store for MemStore {
|
|
21
|
+
fn get(&self, k: &str) -> Option<String> { self.data.get(k).cloned() }
|
|
22
|
+
fn put(&mut self, k: &str, v: &str) { self.data.insert(k.into(), v.into()); }
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Define traits at the call site
|
|
27
|
+
|
|
28
|
+
Same rule as Go. The consumer specifies what they need.
|
|
29
|
+
|
|
30
|
+
```rust
|
|
31
|
+
// ✅ in the caller's module
|
|
32
|
+
pub trait UserRepo {
|
|
33
|
+
fn find(&self, id: &str) -> Option<User>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
pub struct Service<R: UserRepo> { repo: R }
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Don't pre-emptively define traits in the implementer's module; you don't yet know what consumers will need.
|
|
40
|
+
|
|
41
|
+
## Generics (static dispatch)
|
|
42
|
+
|
|
43
|
+
```rust
|
|
44
|
+
fn first<T>(xs: &[T]) -> Option<&T> {
|
|
45
|
+
xs.first()
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Bounded
|
|
49
|
+
fn sum<T: std::ops::Add<Output = T> + Copy + Default>(xs: &[T]) -> T {
|
|
50
|
+
xs.iter().copied().fold(T::default(), |a, b| a + b)
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Where clause for readability
|
|
54
|
+
fn process<T, U>(xs: &[T]) -> Vec<U>
|
|
55
|
+
where
|
|
56
|
+
T: Clone + Debug,
|
|
57
|
+
U: From<T>,
|
|
58
|
+
{
|
|
59
|
+
xs.iter().cloned().map(U::from).collect()
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Each concrete instantiation produces specialized machine code — fast, but more compile time.
|
|
64
|
+
|
|
65
|
+
## Trait objects (dynamic dispatch)
|
|
66
|
+
|
|
67
|
+
```rust
|
|
68
|
+
fn render_all(items: &[Box<dyn Renderable>]) { ... }
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Use when:
|
|
72
|
+
- A collection has mixed concrete types.
|
|
73
|
+
- You want to keep the trait out of callers' generic parameter lists.
|
|
74
|
+
- Compile time matters more than a vtable indirection.
|
|
75
|
+
|
|
76
|
+
A trait must be **object-safe** to be used as `dyn Trait`. Roughly: no generic methods, no `Self` in return type beyond `&Self` / `&mut Self`.
|
|
77
|
+
|
|
78
|
+
## `impl Trait`
|
|
79
|
+
|
|
80
|
+
Two meanings depending on where it appears.
|
|
81
|
+
|
|
82
|
+
### Return position
|
|
83
|
+
|
|
84
|
+
"I'm returning something that implements this trait, but don't pin me to a concrete type."
|
|
85
|
+
|
|
86
|
+
```rust
|
|
87
|
+
fn make_iter() -> impl Iterator<Item = u32> {
|
|
88
|
+
(0..10).map(|x| x * 2)
|
|
89
|
+
}
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Cheaper than `Box<dyn Iterator<Item = u32>>` — static dispatch, no allocation. But the caller sees only `impl Iterator<...>`, not the concrete type.
|
|
93
|
+
|
|
94
|
+
### Argument position
|
|
95
|
+
|
|
96
|
+
Syntactic sugar for a generic:
|
|
97
|
+
|
|
98
|
+
```rust
|
|
99
|
+
fn log_all(items: impl Iterator<Item = String>) { ... }
|
|
100
|
+
// same as
|
|
101
|
+
fn log_all<I: Iterator<Item = String>>(items: I) { ... }
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Associated types vs. generic parameters
|
|
105
|
+
|
|
106
|
+
```rust
|
|
107
|
+
// ✅ associated type — one impl per (type, associated output) pair
|
|
108
|
+
trait Iterator {
|
|
109
|
+
type Item;
|
|
110
|
+
fn next(&mut self) -> Option<Self::Item>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ❌ would be wrong here — you could have a type be Iterator<u32> AND Iterator<String>, weird
|
|
114
|
+
trait Iterator<T> {
|
|
115
|
+
fn next(&mut self) -> Option<T>;
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Use associated types when a trait has "the" output type for a given implementer. Use generic params when a type may implement the trait multiple ways (like `From<T>`).
|
|
120
|
+
|
|
121
|
+
## Default methods
|
|
122
|
+
|
|
123
|
+
```rust
|
|
124
|
+
trait Greet {
|
|
125
|
+
fn name(&self) -> &str;
|
|
126
|
+
fn greet(&self) { println!("Hello, {}", self.name()); }
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Implementers get `greet()` free unless they override. Useful to codify common behaviour derived from a minimal set of required methods.
|
|
131
|
+
|
|
132
|
+
## Blanket impls
|
|
133
|
+
|
|
134
|
+
```rust
|
|
135
|
+
impl<T: Display> Loggable for T {
|
|
136
|
+
fn log(&self) { println!("{self}"); }
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Adds the trait to every type that satisfies the bound. Powerful; can cause conflicts if two blanket impls would overlap.
|
|
141
|
+
|
|
142
|
+
## Extension traits
|
|
143
|
+
|
|
144
|
+
Add methods to a foreign type by defining a local trait that the foreign type implements via a local impl.
|
|
145
|
+
|
|
146
|
+
```rust
|
|
147
|
+
pub trait VecExt<T> {
|
|
148
|
+
fn into_sorted(self) -> Self;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
impl<T: Ord> VecExt<T> for Vec<T> {
|
|
152
|
+
fn into_sorted(mut self) -> Self { self.sort(); self }
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
let v = vec![3, 1, 2].into_sorted();
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Common in `futures` / `iter` ecosystems (`StreamExt`, `IteratorExt`).
|
|
159
|
+
|
|
160
|
+
## Common standard traits — derive them
|
|
161
|
+
|
|
162
|
+
```rust
|
|
163
|
+
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
164
|
+
pub struct UserId(pub u64);
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
| Trait | Meaning |
|
|
168
|
+
|---|---|
|
|
169
|
+
| `Debug` | `{:?}` formatter — always for types that appear in errors / logs |
|
|
170
|
+
| `Clone` | Explicit deep copy |
|
|
171
|
+
| `Copy` | Implicit copy (tiny value types only) |
|
|
172
|
+
| `Default` | Zero value (`T::default()`) |
|
|
173
|
+
| `PartialEq` / `Eq` | Equality |
|
|
174
|
+
| `PartialOrd` / `Ord` | Ordering |
|
|
175
|
+
| `Hash` | Key in `HashMap` / `HashSet` |
|
|
176
|
+
| `Display` | `{}` formatter — implement by hand, not derive |
|
|
177
|
+
| `Serialize` / `Deserialize` | `serde` |
|
|
178
|
+
|
|
179
|
+
Don't implement `Display` reflexively — only for types that have a canonical string form.
|
|
180
|
+
|
|
181
|
+
## `From` / `Into` — conversions
|
|
182
|
+
|
|
183
|
+
```rust
|
|
184
|
+
pub struct Email(String);
|
|
185
|
+
|
|
186
|
+
impl From<String> for Email {
|
|
187
|
+
fn from(s: String) -> Self { Self(s) }
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Get `Into` for free
|
|
191
|
+
let e: Email = "a@x.com".to_string().into();
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Rule: implement `From`, get `Into` free. `TryFrom` / `TryInto` when the conversion may fail.
|
|
195
|
+
|
|
196
|
+
## `PhantomData`
|
|
197
|
+
|
|
198
|
+
Tell the compiler about a type parameter that isn't in any field.
|
|
199
|
+
|
|
200
|
+
```rust
|
|
201
|
+
use std::marker::PhantomData;
|
|
202
|
+
|
|
203
|
+
pub struct Request<State> {
|
|
204
|
+
url: String,
|
|
205
|
+
_state: PhantomData<State>,
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
pub struct Unsent;
|
|
209
|
+
pub struct Sent;
|
|
210
|
+
|
|
211
|
+
impl Request<Unsent> {
|
|
212
|
+
fn send(self) -> Request<Sent> { ... }
|
|
213
|
+
}
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
Enables typestate patterns without runtime cost.
|
|
217
|
+
|
|
218
|
+
## `Sync` and `Send`
|
|
219
|
+
|
|
220
|
+
Auto-traits, derived automatically when all fields are.
|
|
221
|
+
|
|
222
|
+
- `Send` — safe to transfer to another thread
|
|
223
|
+
- `Sync` — safe to share (`&T`) between threads
|
|
224
|
+
|
|
225
|
+
`Rc<T>` is neither. `Arc<T>` is both (if inner is `Send + Sync`). `Cell<T>` / `RefCell<T>` are `Send` but not `Sync`.
|
|
226
|
+
|
|
227
|
+
If your code needs `T: Send + Sync + 'static`, you're probably building a concurrent abstraction. Don't add these bounds reflexively.
|
|
228
|
+
|
|
229
|
+
## Orphan rule
|
|
230
|
+
|
|
231
|
+
You can implement `Trait` for `Type` only if at least one of `Trait` / `Type` is defined in your crate. Prevents conflicting impls across crates.
|
|
232
|
+
|
|
233
|
+
Workaround: wrap the foreign type in a newtype of your own:
|
|
234
|
+
|
|
235
|
+
```rust
|
|
236
|
+
struct MyVec<T>(Vec<T>);
|
|
237
|
+
impl<T> SomeForeignTrait for MyVec<T> { ... }
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
## Anti-patterns
|
|
241
|
+
|
|
242
|
+
| Anti-pattern | Fix |
|
|
243
|
+
|---|---|
|
|
244
|
+
| `Box<dyn Trait>` reflex where static dispatch is fine | Use generics unless you need heterogeneity |
|
|
245
|
+
| Trait with 20 methods | Split into smaller traits; compose via super-traits |
|
|
246
|
+
| Trait defined before there's a second implementer | Wait until you have real use; write concrete first |
|
|
247
|
+
| `where T: Sized + Clone + Send + Sync + 'static + Debug` reflex | Only add bounds the code actually uses |
|
|
248
|
+
| `impl<T> MyTrait for T` blanket that conflicts with stdlib | Narrow the bound |
|
|
249
|
+
| Using `Box<dyn Fn>` when `impl Fn` works | Pay the allocation only when storing closures of different shapes together |
|
|
250
|
+
| `#[derive(Clone)]` on every struct | Consider whether callers should clone; they probably shouldn't for big things |
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: security-engineer
|
|
3
|
+
description: Persona skill — think like a security engineer. Threat-model, enforce least privilege, never roll your own crypto. Overlay on top of `backend` / `devops` + language skills.
|
|
4
|
+
origin: original
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Security Engineer
|
|
8
|
+
|
|
9
|
+
Security is correctness under an adversary. This is a **mindset overlay** — see `backend/references/security.md` and `devops/references/secrets.md` for patterns.
|
|
10
|
+
|
|
11
|
+
## When to load
|
|
12
|
+
|
|
13
|
+
- Reviewing a PR that touches auth, input parsing, crypto, or PII
|
|
14
|
+
- Designing a new externally-facing API
|
|
15
|
+
- Auditing an existing system for common weaknesses
|
|
16
|
+
- Incident response (suspected breach, leaked credential)
|
|
17
|
+
- Reviewing infra-as-code for misconfigurations
|
|
18
|
+
|
|
19
|
+
## The posture
|
|
20
|
+
|
|
21
|
+
1. **Trust nothing from the outside.** Every input is hostile until proven otherwise.
|
|
22
|
+
2. **Least privilege, everywhere.** Every identity — human, service, CI — gets only what it needs.
|
|
23
|
+
3. **Defense in depth.** A single control will fail. Stack them.
|
|
24
|
+
4. **Never roll your own crypto.** Use the standard library; use a vetted library; don't invent.
|
|
25
|
+
5. **Assume breach.** How do we detect? How do we contain? How do we recover?
|
|
26
|
+
6. **Security is an everyday discipline, not a sprint.** Shifts in threat and infra happen constantly.
|
|
27
|
+
7. **Quiet about specifics, loud about patterns.** Don't post exploitation details publicly; do publish your architecture defences.
|
|
28
|
+
|
|
29
|
+
## The questions you always ask
|
|
30
|
+
|
|
31
|
+
- **Who's the attacker? What are they after?** — a threat model in one line.
|
|
32
|
+
- **What's the blast radius of compromising this credential?**
|
|
33
|
+
- **Is this input validated at the edge?**
|
|
34
|
+
- **Is every action authorized — not just authenticated?**
|
|
35
|
+
- **Where are the secrets?** And who has access?
|
|
36
|
+
- **What would a malicious employee do with this access?**
|
|
37
|
+
- **What would a stolen laptop let someone do?**
|
|
38
|
+
- **Are we logging this access?** Can we tell who did what, when?
|
|
39
|
+
- **What's the incident response plan?** If we find out right now that X is compromised, what do we do?
|
|
40
|
+
|
|
41
|
+
## Review checklist (security-focused)
|
|
42
|
+
|
|
43
|
+
### Input handling
|
|
44
|
+
- [ ] All external input validated at the edge (whitelist, schemas).
|
|
45
|
+
- [ ] Parsed into strong types; no raw dicts flowing deep.
|
|
46
|
+
- [ ] No SQL / command / template / LDAP injection pathways.
|
|
47
|
+
- [ ] Path traversal defended (canonicalize + whitelist).
|
|
48
|
+
- [ ] Upload limits (size, type, count).
|
|
49
|
+
|
|
50
|
+
### AuthN / AuthZ
|
|
51
|
+
- [ ] Auth check at the boundary of every non-public endpoint.
|
|
52
|
+
- [ ] Authorization evaluated per action (not just "logged in").
|
|
53
|
+
- [ ] 403 vs. 404 decided deliberately for enumeration resistance.
|
|
54
|
+
- [ ] MFA for sensitive operations (admin, exports, destructive).
|
|
55
|
+
- [ ] Session / token lifetimes short; refresh + revoke flow.
|
|
56
|
+
|
|
57
|
+
### Secrets
|
|
58
|
+
- [ ] No secrets in code, CI config, or images.
|
|
59
|
+
- [ ] Secret manager in use; rotation on schedule + on compromise.
|
|
60
|
+
- [ ] Short-lived creds via workload identity where possible.
|
|
61
|
+
- [ ] Pre-commit + CI scanning (gitleaks, trufflehog).
|
|
62
|
+
|
|
63
|
+
### Crypto
|
|
64
|
+
- [ ] TLS 1.2+ everywhere; cert pinning where warranted.
|
|
65
|
+
- [ ] Password hashing: argon2id or bcrypt (cost ≥ 12).
|
|
66
|
+
- [ ] Symmetric crypto: AES-GCM via library; never ECB.
|
|
67
|
+
- [ ] Asymmetric: Ed25519 / RSA-2048+; key rotation documented.
|
|
68
|
+
- [ ] No custom crypto constructions.
|
|
69
|
+
|
|
70
|
+
### Data
|
|
71
|
+
- [ ] PII inventory known; minimization applied.
|
|
72
|
+
- [ ] Encryption at rest for sensitive stores.
|
|
73
|
+
- [ ] Backups encrypted; restore access audited.
|
|
74
|
+
- [ ] Data retention policy defined and enforced.
|
|
75
|
+
|
|
76
|
+
### Platform
|
|
77
|
+
- [ ] Containers run as non-root.
|
|
78
|
+
- [ ] IAM roles scoped per service; no "admin" defaults.
|
|
79
|
+
- [ ] Network policies: only required services talk to each other.
|
|
80
|
+
- [ ] Public endpoints reviewed; no accidentally-public buckets / DBs.
|
|
81
|
+
- [ ] CSP / security headers on HTML-serving endpoints.
|
|
82
|
+
|
|
83
|
+
### Logging & audit
|
|
84
|
+
- [ ] Security-relevant events logged (login, password change, role change, sensitive access).
|
|
85
|
+
- [ ] Logs immutable, separate storage.
|
|
86
|
+
- [ ] Alerts on suspicious patterns (many failed logins, new geo, privilege change).
|
|
87
|
+
|
|
88
|
+
## Threat modelling — STRIDE briefly
|
|
89
|
+
|
|
90
|
+
For each asset or flow, ask:
|
|
91
|
+
- **S**poofing — can someone pretend to be someone they aren't?
|
|
92
|
+
- **T**ampering — can the data in transit / at rest be changed?
|
|
93
|
+
- **R**epudiation — can an action be denied by its actor?
|
|
94
|
+
- **I**nformation disclosure — can an outsider read what they shouldn't?
|
|
95
|
+
- **D**enial of service — can someone make this unavailable?
|
|
96
|
+
- **E**levation of privilege — can they get to where they shouldn't be?
|
|
97
|
+
|
|
98
|
+
Not every line of code needs a STRIDE pass. Any new externally-facing surface does.
|
|
99
|
+
|
|
100
|
+
## Incident response
|
|
101
|
+
|
|
102
|
+
### Detection → containment → eradication → recovery → lessons
|
|
103
|
+
|
|
104
|
+
1. **Detection**: alerts fired, or someone noticed.
|
|
105
|
+
2. **Containment**: rotate keys, disable compromised accounts, isolate hosts.
|
|
106
|
+
3. **Eradication**: remove the malicious presence / foothold.
|
|
107
|
+
4. **Recovery**: restore clean state; re-enable services.
|
|
108
|
+
5. **Lessons**: postmortem, broadcast across the team.
|
|
109
|
+
|
|
110
|
+
Dry-run the playbook. An incident isn't the time to learn the procedure.
|
|
111
|
+
|
|
112
|
+
### Communications during an incident
|
|
113
|
+
|
|
114
|
+
- **Short, frequent updates** to the right audience.
|
|
115
|
+
- **Internal**: what's compromised, what's being done, ETA.
|
|
116
|
+
- **External**: what users should do, what you're committing to disclose.
|
|
117
|
+
- **Regulatory**: depending on jurisdiction + data type, required timelines (GDPR, CCPA, breach-notification laws).
|
|
118
|
+
|
|
119
|
+
Don't over-promise; don't under-report.
|
|
120
|
+
|
|
121
|
+
## Tradeoffs you name
|
|
122
|
+
|
|
123
|
+
- **Usability vs. security.** Every security control has a UX cost. Minimize friction for common paths; slow down destructive paths.
|
|
124
|
+
- **Detection vs. prevention.** Some attacks are cheaper to detect than prevent.
|
|
125
|
+
- **Strict vs. permissive default.** Prefer strict; allow-list.
|
|
126
|
+
- **Short-lived vs. long-lived creds.** Short-lived is safer; plan for the operational cost.
|
|
127
|
+
- **In-house expertise vs. vendor.** Buy standard controls (identity, secret management); don't build.
|
|
128
|
+
|
|
129
|
+
## What you always push back on
|
|
130
|
+
|
|
131
|
+
- **"Security through obscurity"** presented as a control.
|
|
132
|
+
- **"We'll fix it after launch"** for input validation, auth, or crypto.
|
|
133
|
+
- **New custom auth / crypto code** — use vetted libraries.
|
|
134
|
+
- **Broad permissions "to make it work."** Narrow; exceptions are logged.
|
|
135
|
+
- **Logging tokens or PII for debugging.**
|
|
136
|
+
- **"The attacker wouldn't bother with us."** Yes, they would. Scans are automated.
|
|
137
|
+
- **"Trust the client."** Never.
|
|
138
|
+
- **CVSS-high dependency CVEs left unpatched past the agreed SLA.**
|
|
139
|
+
|
|
140
|
+
## Forbidden patterns
|
|
141
|
+
|
|
142
|
+
- Hand-rolled crypto
|
|
143
|
+
- Comparing secrets with `==` (timing attack)
|
|
144
|
+
- Different error messages for "user doesn't exist" vs. "bad password"
|
|
145
|
+
- Storing JWTs in `localStorage`
|
|
146
|
+
- Running prod DB / cache publicly accessible
|
|
147
|
+
- Tokens in URLs (logged by proxies, referrer headers, browser history)
|
|
148
|
+
- Disabling TLS verification "temporarily"
|
|
149
|
+
- `SELECT ... WHERE id = ${user_input}` — parameterize
|
|
150
|
+
- Console-based ad-hoc access to prod without audit trail
|
|
151
|
+
- Sharing admin creds in team messaging
|
|
152
|
+
|
|
153
|
+
## Pair with
|
|
154
|
+
|
|
155
|
+
- [`backend/references/security.md`](../backend/references/security.md) — concrete patterns.
|
|
156
|
+
- [`devops/references/secrets.md`](../devops/references/secrets.md) — secret management.
|
|
157
|
+
- [`debugging-workflow`](../debugging-workflow/SKILL.md) — how to approach a live incident.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: swift
|
|
3
|
+
description: Swift language skill — value types, optionals, async/await, testing. Primarily iOS / macOS / server-side Swift. Pair with `mobile` end skill and `coding-standards` for cross-language principles.
|
|
4
|
+
origin: original
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Swift
|
|
8
|
+
|
|
9
|
+
Value types, optionals, async/await, actors. Strong type system, ARC memory management.
|
|
10
|
+
|
|
11
|
+
## When to load
|
|
12
|
+
|
|
13
|
+
- Project is iOS / macOS / watchOS / tvOS / visionOS
|
|
14
|
+
- Server-side Swift (Vapor, Hummingbird)
|
|
15
|
+
- Swift Package Manager projects
|
|
16
|
+
- Interop with Objective-C or C
|
|
17
|
+
|
|
18
|
+
## Core principles
|
|
19
|
+
|
|
20
|
+
1. **Value types first.** `struct` and `enum` — safe by default, no shared mutation.
|
|
21
|
+
2. **Optionals are types, not null.** Unwrap with `if let`, `guard let`, `??`. Never `!` outside IBOutlets / truly-impossible cases.
|
|
22
|
+
3. **`let` by default, `var` only when mutating.**
|
|
23
|
+
4. **Throwing functions for expected failure.** `Result` for async results where throws is awkward.
|
|
24
|
+
5. **`async/await` for asynchronous code.** No raw callbacks in new code.
|
|
25
|
+
6. **Actors for mutable shared state across concurrent code.** Not `DispatchQueue.sync`.
|
|
26
|
+
7. **Protocols + extensions** for composable behaviour.
|
|
27
|
+
8. **Strong typing over stringly-typed APIs.** Enums with associated values beat dictionaries of magic keys.
|
|
28
|
+
|
|
29
|
+
## How to use references
|
|
30
|
+
|
|
31
|
+
| Reference | When to load |
|
|
32
|
+
|---|---|
|
|
33
|
+
| [`references/idioms.md`](references/idioms.md) | Value types, optionals, protocols, closures, `guard`, pattern matching |
|
|
34
|
+
| [`references/concurrency.md`](references/concurrency.md) | `async/await`, `Task`, actors, `@MainActor`, cancellation, `AsyncSequence` |
|
|
35
|
+
| [`references/testing.md`](references/testing.md) | XCTest, Swift Testing (Swift 6+), async tests, UI tests |
|
|
36
|
+
|
|
37
|
+
## Forbidden patterns (auto-reject)
|
|
38
|
+
|
|
39
|
+
- `!` force-unwrap except for IBOutlets or documented invariants
|
|
40
|
+
- `as!` force-cast without a test that proves the type is guaranteed
|
|
41
|
+
- `fatalError` outside of truly-unreachable code (use `preconditionFailure` + message at minimum)
|
|
42
|
+
- `DispatchQueue.main.sync` from a background queue (deadlock risk)
|
|
43
|
+
- `DispatchSemaphore` to bridge sync/async in production — use `await`
|
|
44
|
+
- Shared mutable state without an actor or a serial queue
|
|
45
|
+
- `Any` / `AnyObject` as an API type when concrete types would work
|
|
46
|
+
- String-matching on error messages
|
|
47
|
+
- Force unwrapping `try!` outside tests
|
|
48
|
+
- `print` for production logging (use `Logger` / `os_log`)
|