fix: harden unicode safety checks

This commit is contained in:
Affaan Mustafa
2026-03-29 08:59:06 -04:00
parent dd675d4258
commit 866d9ebb53
239 changed files with 3780 additions and 3962 deletions

View File

@@ -39,7 +39,7 @@ AI 编写修复 → AI 审查修复 → AI 表示“看起来正确” → 漏
→ 修复了生产路径,忘记了沙箱路径
→ AI 审核时再次遗漏(第 4 次出现)
修复 4测试在首次运行时立即捕获了问题
修复 4测试在首次运行时立即捕获了问题 PASS:
```
模式:**沙盒/生产环境路径不一致**是 AI 引入的 #1 回归问题。
@@ -249,14 +249,14 @@ User: "バグチェックして" (or "/bug-check")
**频率**:最常见(在 4 个回归问题中观察到 3 个)
```typescript
// AI adds field to production path only
// FAIL: AI adds field to production path only
if (isSandboxMode()) {
return { data: { id, email, name } }; // Missing new field
}
// Production path
return { data: { id, email, name, notification_settings } };
// Both paths must return the same shape
// PASS: Both paths must return the same shape
if (isSandboxMode()) {
return { data: { id, email, name, notification_settings: null } };
}
@@ -282,7 +282,7 @@ it("sandbox and production return same fields", async () => {
**频率**:在使用 Supabase/Prisma 添加新列时常见
```typescript
// New column added to response but not to SELECT
// FAIL: New column added to response but not to SELECT
const { data } = await supabase
.from("users")
.select("id, email, name") // notification_settings not here
@@ -291,7 +291,7 @@ const { data } = await supabase
return { data: { ...data, notification_settings: data.notification_settings } };
// → notification_settings is always undefined
// Use SELECT * or explicitly include new columns
// PASS: Use SELECT * or explicitly include new columns
const { data } = await supabase
.from("users")
.select("*")
@@ -303,13 +303,13 @@ const { data } = await supabase
**频率**:中等——当向现有组件添加错误处理时
```typescript
// Error state set but old data not cleared
// FAIL: Error state set but old data not cleared
catch (err) {
setError("Failed to load");
// reservations still shows data from previous tab!
}
// Clear related state on error
// PASS: Clear related state on error
catch (err) {
setReservations([]); // Clear stale data
setError("Failed to load");
@@ -319,14 +319,14 @@ catch (err) {
### 模式 4乐观更新未正确回滚
```typescript
// No rollback on failure
// FAIL: No rollback on failure
const handleRemove = async (id: string) => {
setItems(prev => prev.filter(i => i.id !== id));
await fetch(`/api/items/${id}`, { method: "DELETE" });
// If API fails, item is gone from UI but still in DB
};
// Capture previous state and rollback on failure
// PASS: Capture previous state and rollback on failure
const handleRemove = async (id: string) => {
const prevItems = [...items];
setItems(prev => prev.filter(i => i.id !== id));
@@ -362,11 +362,11 @@ const handleRemove = async (id: string) => {
| AI 回归模式 | 测试策略 | 优先级 |
|---|---|---|
| 沙盒/生产环境不匹配 | 断言沙盒模式下响应结构相同 | 🔴 高 |
| SELECT 子句遗漏 | 断言响应中包含所有必需字段 | 🔴 高 |
| 错误状态泄漏 | 断言出错时状态已清理 | 🟡 中 |
| 缺少回滚 | 断言 API 失败时状态已恢复 | 🟡 中 |
| 类型转换掩盖 null | 断言字段不为 undefined | 🟡 中 |
| 沙盒/生产环境不匹配 | 断言沙盒模式下响应结构相同 | 高 |
| SELECT 子句遗漏 | 断言响应中包含所有必需字段 | 高 |
| 错误状态泄漏 | 断言出错时状态已清理 | 中 |
| 缺少回滚 | 断言 API 失败时状态已恢复 | 中 |
| 类型转换掩盖 null | 断言字段不为 undefined | 中 |
## 要 / 不要

View File

@@ -37,10 +37,10 @@ project/
### 依赖规则
```
app → presentation, domain, data, core
presentation → domain, design-system, core
data → domain, core
domain → core (或无依赖)
app → presentation, domain, data, core
presentation → domain, design-system, core
data → domain, core
domain → core (或无依赖)
core → (无依赖)
```

View File

@@ -23,7 +23,7 @@ origin: ECC
### RESTful API 结构
```typescript
// Resource-based URLs
// PASS: Resource-based URLs
GET /api/markets # List resources
GET /api/markets/:id # Get single resource
POST /api/markets # Create resource
@@ -31,7 +31,7 @@ PUT /api/markets/:id # Replace resource
PATCH /api/markets/:id # Update resource
DELETE /api/markets/:id # Delete resource
// Query parameters for filtering, sorting, pagination
// PASS: Query parameters for filtering, sorting, pagination
GET /api/markets?status=active&sort=volume&limit=20&offset=0
```
@@ -131,7 +131,7 @@ export default withAuth(async (req, res) => {
### 查询优化
```typescript
// GOOD: Select only needed columns
// PASS: GOOD: Select only needed columns
const { data } = await supabase
.from('markets')
.select('id, name, status, volume')
@@ -139,7 +139,7 @@ const { data } = await supabase
.order('volume', { ascending: false })
.limit(10)
// BAD: Select everything
// FAIL: BAD: Select everything
const { data } = await supabase
.from('markets')
.select('*')
@@ -148,13 +148,13 @@ const { data } = await supabase
### N+1 查询预防
```typescript
// BAD: N+1 query problem
// FAIL: BAD: N+1 query problem
const markets = await getMarkets()
for (const market of markets) {
market.creator = await getUser(market.creator_id) // N queries
}
// GOOD: Batch fetch
// PASS: GOOD: Batch fetch
const markets = await getMarkets()
const creatorIds = markets.map(m => m.creator_id)
const creators = await getUsers(creatorIds) // 1 query

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "🤝"
emoji: ""
---
# 承运商关系管理

View File

@@ -97,7 +97,7 @@ ORDER BY hour DESC;
### 高效过滤
```sql
-- GOOD: Use indexed columns first
-- PASS: GOOD: Use indexed columns first
SELECT *
FROM markets_analytics
WHERE date >= '2025-01-01'
@@ -106,7 +106,7 @@ WHERE date >= '2025-01-01'
ORDER BY date DESC
LIMIT 100;
-- BAD: Filter on non-indexed columns first
-- FAIL: BAD: Filter on non-indexed columns first
SELECT *
FROM markets_analytics
WHERE volume > 1000
@@ -117,7 +117,7 @@ WHERE volume > 1000
### 聚合
```sql
-- GOOD: Use ClickHouse-specific aggregation functions
-- PASS: GOOD: Use ClickHouse-specific aggregation functions
SELECT
toStartOfDay(created_at) AS day,
market_id,
@@ -130,7 +130,7 @@ WHERE created_at >= today() - INTERVAL 7 DAY
GROUP BY day, market_id
ORDER BY day DESC, total_volume DESC;
-- Use quantile for percentiles (more efficient than percentile)
-- PASS: Use quantile for percentiles (more efficient than percentile)
SELECT
quantile(0.50)(trade_size) AS median,
quantile(0.95)(trade_size) AS p95,
@@ -173,7 +173,7 @@ const clickhouse = new ClickHouse({
}
})
// Batch insert (efficient)
// PASS: Batch insert (efficient)
async function bulkInsertTrades(trades: Trade[]) {
const values = trades.map(trade => `(
'${trade.id}',
@@ -189,7 +189,7 @@ async function bulkInsertTrades(trades: Trade[]) {
`).toPromise()
}
// Individual inserts (slow)
// FAIL: Individual inserts (slow)
async function insertTrade(trade: Trade) {
// Don't do this in a loop!
await clickhouse.query(`

View File

@@ -52,12 +52,12 @@ origin: ECC
### 变量命名
```typescript
// GOOD: Descriptive names
// PASS: GOOD: Descriptive names
const marketSearchQuery = 'election'
const isUserAuthenticated = true
const totalRevenue = 1000
// BAD: Unclear names
// FAIL: BAD: Unclear names
const q = 'election'
const flag = true
const x = 1000
@@ -66,12 +66,12 @@ const x = 1000
### 函数命名
```typescript
// GOOD: Verb-noun pattern
// PASS: GOOD: Verb-noun pattern
async function fetchMarketData(marketId: string) { }
function calculateSimilarity(a: number[], b: number[]) { }
function isValidEmail(email: string): boolean { }
// BAD: Unclear or noun-only
// FAIL: BAD: Unclear or noun-only
async function market(id: string) { }
function similarity(a, b) { }
function email(e) { }
@@ -80,7 +80,7 @@ function email(e) { }
### 不可变性模式 (关键)
```typescript
// ALWAYS use spread operator
// PASS: ALWAYS use spread operator
const updatedUser = {
...user,
name: 'New Name'
@@ -88,7 +88,7 @@ const updatedUser = {
const updatedArray = [...items, newItem]
// NEVER mutate directly
// FAIL: NEVER mutate directly
user.name = 'New Name' // BAD
items.push(newItem) // BAD
```
@@ -96,7 +96,7 @@ items.push(newItem) // BAD
### 错误处理
```typescript
// GOOD: Comprehensive error handling
// PASS: GOOD: Comprehensive error handling
async function fetchData(url: string) {
try {
const response = await fetch(url)
@@ -112,7 +112,7 @@ async function fetchData(url: string) {
}
}
// BAD: No error handling
// FAIL: BAD: No error handling
async function fetchData(url) {
const response = await fetch(url)
return response.json()
@@ -122,14 +122,14 @@ async function fetchData(url) {
### Async/Await 最佳实践
```typescript
// GOOD: Parallel execution when possible
// PASS: GOOD: Parallel execution when possible
const [users, markets, stats] = await Promise.all([
fetchUsers(),
fetchMarkets(),
fetchStats()
])
// BAD: Sequential when unnecessary
// FAIL: BAD: Sequential when unnecessary
const users = await fetchUsers()
const markets = await fetchMarkets()
const stats = await fetchStats()
@@ -138,7 +138,7 @@ const stats = await fetchStats()
### 类型安全
```typescript
// GOOD: Proper types
// PASS: GOOD: Proper types
interface Market {
id: string
name: string
@@ -150,7 +150,7 @@ function getMarket(id: string): Promise<Market> {
// Implementation
}
// BAD: Using 'any'
// FAIL: BAD: Using 'any'
function getMarket(id: any): Promise<any> {
// Implementation
}
@@ -161,7 +161,7 @@ function getMarket(id: any): Promise<any> {
### 组件结构
```typescript
// GOOD: Functional component with types
// PASS: GOOD: Functional component with types
interface ButtonProps {
children: React.ReactNode
onClick: () => void
@@ -186,7 +186,7 @@ export function Button({
)
}
// BAD: No types, unclear structure
// FAIL: BAD: No types, unclear structure
export function Button(props) {
return <button onClick={props.onClick}>{props.children}</button>
}
@@ -195,7 +195,7 @@ export function Button(props) {
### 自定义 Hooks
```typescript
// GOOD: Reusable custom hook
// PASS: GOOD: Reusable custom hook
export function useDebounce<T>(value: T, delay: number): T {
const [debouncedValue, setDebouncedValue] = useState<T>(value)
@@ -217,25 +217,25 @@ const debouncedQuery = useDebounce(searchQuery, 500)
### 状态管理
```typescript
// GOOD: Proper state updates
// PASS: GOOD: Proper state updates
const [count, setCount] = useState(0)
// Functional update for state based on previous state
setCount(prev => prev + 1)
// BAD: Direct state reference
// FAIL: BAD: Direct state reference
setCount(count + 1) // Can be stale in async scenarios
```
### 条件渲染
```typescript
// GOOD: Clear conditional rendering
// PASS: GOOD: Clear conditional rendering
{isLoading && <Spinner />}
{error && <ErrorMessage error={error} />}
{data && <DataDisplay data={data} />}
// BAD: Ternary hell
// FAIL: BAD: Ternary hell
{isLoading ? <Spinner /> : error ? <ErrorMessage error={error} /> : data ? <DataDisplay data={data} /> : null}
```
@@ -258,7 +258,7 @@ GET /api/markets?status=active&limit=10&offset=0
### 响应格式
```typescript
// GOOD: Consistent response structure
// PASS: GOOD: Consistent response structure
interface ApiResponse<T> {
success: boolean
data?: T
@@ -289,7 +289,7 @@ return NextResponse.json({
```typescript
import { z } from 'zod'
// GOOD: Schema validation
// PASS: GOOD: Schema validation
const CreateMarketSchema = z.object({
name: z.string().min(1).max(200),
description: z.string().min(1).max(2000),
@@ -352,14 +352,14 @@ types/market.types.ts # 使用 .types 后缀的驼峰命名法
### 何时添加注释
```typescript
// GOOD: Explain WHY, not WHAT
// PASS: GOOD: Explain WHY, not WHAT
// Use exponential backoff to avoid overwhelming the API during outages
const delay = Math.min(1000 * Math.pow(2, retryCount), 30000)
// Deliberately using mutation here for performance with large arrays
items.push(newItem)
// BAD: Stating the obvious
// FAIL: BAD: Stating the obvious
// Increment counter by 1
count++
@@ -399,12 +399,12 @@ export async function searchMarkets(
```typescript
import { useMemo, useCallback } from 'react'
// GOOD: Memoize expensive computations
// PASS: GOOD: Memoize expensive computations
const sortedMarkets = useMemo(() => {
return markets.sort((a, b) => b.volume - a.volume)
}, [markets])
// GOOD: Memoize callbacks
// PASS: GOOD: Memoize callbacks
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
@@ -415,7 +415,7 @@ const handleSearch = useCallback((query: string) => {
```typescript
import { lazy, Suspense } from 'react'
// GOOD: Lazy load heavy components
// PASS: GOOD: Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'))
export function Dashboard() {
@@ -430,13 +430,13 @@ export function Dashboard() {
### 数据库查询
```typescript
// GOOD: Select only needed columns
// PASS: GOOD: Select only needed columns
const { data } = await supabase
.from('markets')
.select('id, name, status')
.limit(10)
// BAD: Select everything
// FAIL: BAD: Select everything
const { data } = await supabase
.from('markets')
.select('*')
@@ -463,12 +463,12 @@ test('calculates similarity correctly', () => {
### 测试命名
```typescript
// GOOD: Descriptive test names
// PASS: GOOD: Descriptive test names
test('returns empty array when no markets match query', () => { })
test('throws error when OpenAI API key is missing', () => { })
test('falls back to substring search when Redis unavailable', () => { })
// BAD: Vague test names
// FAIL: BAD: Vague test names
test('works', () => { })
test('test search', () => { })
```
@@ -480,12 +480,12 @@ test('test search', () => { })
### 1. 长函数
```typescript
// BAD: Function > 50 lines
// FAIL: BAD: Function > 50 lines
function processMarketData() {
// 100 lines of code
}
// GOOD: Split into smaller functions
// PASS: GOOD: Split into smaller functions
function processMarketData() {
const validated = validateData()
const transformed = transformData(validated)
@@ -496,7 +496,7 @@ function processMarketData() {
### 2. 深层嵌套
```typescript
// BAD: 5+ levels of nesting
// FAIL: BAD: 5+ levels of nesting
if (user) {
if (user.isAdmin) {
if (market) {
@@ -509,7 +509,7 @@ if (user) {
}
}
// GOOD: Early returns
// PASS: GOOD: Early returns
if (!user) return
if (!user.isAdmin) return
if (!market) return
@@ -522,11 +522,11 @@ if (!hasPermission) return
### 3. 魔法数字
```typescript
// BAD: Unexplained numbers
// FAIL: BAD: Unexplained numbers
if (retryCount > 3) { }
setTimeout(callback, 500)
// GOOD: Named constants
// PASS: GOOD: Named constants
const MAX_RETRIES = 3
const DEBOUNCE_DELAY_MS = 500

View File

@@ -94,7 +94,7 @@ origin: ECC
│ CLAUDE.md │ N │ ~X,XXX │
└─────────────────┴────────┴───────────┘
发现的问题 (N)
WARNING: 发现的问题 (N)
[按可节省词元数排序]
前 3 项优化建议:

View File

@@ -14,7 +14,7 @@ origin: ECC
Start
|
+-- 需要严格的 CI/PR 控制? -- yes --> continuous-pr
|
|
+-- 需要 RFC 分解? -- yes --> rfc-dag
|
+-- 需要探索性并行生成? -- yes --> infinite

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "🌐"
emoji: ""
---
# 海关与贸易合规

View File

@@ -363,7 +363,7 @@ DJANGO 验证报告
✓ 无硬编码密钥
✓ 包含迁移文件
建议:⚠️ 部署前修复 pip-audit 发现的漏洞
建议:WARNING: 部署前修复 pip-audit 发现的漏洞
后续步骤:
1. 更新存在漏洞的依赖项

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: ""
emoji: ""
---
# 能源采购

View File

@@ -23,7 +23,7 @@ origin: ECC
### 组合优于继承
```typescript
// GOOD: Component composition
// PASS: GOOD: Component composition
interface CardProps {
children: React.ReactNode
variant?: 'default' | 'outlined'
@@ -294,17 +294,17 @@ export function useMarkets() {
### 记忆化
```typescript
// useMemo for expensive computations
// PASS: useMemo for expensive computations
const sortedMarkets = useMemo(() => {
return markets.sort((a, b) => b.volume - a.volume)
}, [markets])
// useCallback for functions passed to children
// PASS: useCallback for functions passed to children
const handleSearch = useCallback((query: string) => {
setSearchQuery(query)
}, [])
// React.memo for pure components
// PASS: React.memo for pure components
export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
return (
<div className="market-card">
@@ -320,7 +320,7 @@ export const MarketCard = React.memo<MarketCardProps>(({ market }) => {
```typescript
import { lazy, Suspense } from 'react'
// Lazy load heavy components
// PASS: Lazy load heavy components
const HeavyChart = lazy(() => import('./HeavyChart'))
const ThreeJsBackground = lazy(() => import('./ThreeJsBackground'))
@@ -515,7 +515,7 @@ export class ErrorBoundary extends React.Component<
```typescript
import { motion, AnimatePresence } from 'framer-motion'
// List animations
// PASS: List animations
export function AnimatedMarketList({ markets }: { markets: Market[] }) {
return (
<AnimatePresence>
@@ -534,7 +534,7 @@ export function AnimatedMarketList({ markets }: { markets: Market[] }) {
)
}
// Modal animations
// PASS: Modal animations
export function Modal({ isOpen, onClose, children }: ModalProps) {
return (
<AnimatePresence>

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "📊"
emoji: ""
---
# 库存需求规划

View File

@@ -38,12 +38,12 @@ origin: ECC
┌─────────────────────────────────────────────┐
│ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 调度 │─────│ 评估 │ │
│ │ 调度 │─────│ 评估 │ │
│ └──────────┘ └──────────┘ │
│ ▲ │ │
│ │ ▼ │
│ ┌──────────┐ ┌──────────┐ │
│ │ 循环 │─────│ 优化 │ │
│ │ 循环 │─────│ 优化 │ │
│ └──────────┘ └──────────┘ │
│ │
│ 最多3次循环然后继续 │

View File

@@ -26,22 +26,22 @@ origin: ECC
## 命名
```java
// Classes/Records: PascalCase
// PASS: Classes/Records: PascalCase
public class MarketService {}
public record Money(BigDecimal amount, Currency currency) {}
// Methods/fields: camelCase
// PASS: Methods/fields: camelCase
private final MarketRepository marketRepository;
public Market findBySlug(String slug) {}
// Constants: UPPER_SNAKE_CASE
// PASS: Constants: UPPER_SNAKE_CASE
private static final int MAX_PAGE_SIZE = 100;
```
## 不可变性
```java
// Favor records and final fields
// PASS: Favor records and final fields
public record MarketDto(Long id, String name, MarketStatus status) {}
public class Market {
@@ -54,10 +54,10 @@ public class Market {
## Optional 使用
```java
// Return Optional from find* methods
// PASS: Return Optional from find* methods
Optional<Market> market = marketRepository.findBySlug(slug);
// Map/flatMap instead of get()
// PASS: Map/flatMap instead of get()
return market
.map(MarketResponse::from)
.orElseThrow(() -> new EntityNotFoundException("Market not found"));
@@ -66,13 +66,13 @@ return market
## Streams 最佳实践
```java
// Use streams for transformations, keep pipelines short
// PASS: Use streams for transformations, keep pipelines short
List<String> names = markets.stream()
.map(Market::name)
.filter(Objects::nonNull)
.toList();
// Avoid complex nested streams; prefer loops for clarity
// FAIL: Avoid complex nested streams; prefer loops for clarity
```
## 异常

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "📦"
emoji: ""
---
# 物流异常管理

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "🏭"
emoji: ""
---
# 生产排程

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "🔍"
emoji: ""
---
# 质量与不合格品管理

View File

@@ -7,7 +7,7 @@ origin: ECC
metadata:
author: evos
clawdbot:
emoji: "🔄"
emoji: ""
---
# 退货与逆向物流

View File

@@ -75,21 +75,21 @@ bash ~/.claude/skills/rules-distill/scripts/scan-rules.sh
**仅当**满足以下**所有**条件时,才包含一个候选原则:
1. **出现在 2+ 项技能中**:仅出现在一项技能中的原则应保留在该技能中
2. **可操作的行为改变**:可以写成“做 X”或“不要做 Y”的形式——而不是“X 很重要”
3. **明确的违规风险**如果忽略此原则会出什么问题1 句话)
4. **尚未存在于规则中**:检查全部规则文本——包括以不同措辞表达的概念
1. **出现在 2+ 项技能中**:仅出现在一项技能中的原则应保留在该技能中
2. **可操作的行为改变**:可以写成“做 X”或“不要做 Y”的形式——而不是“X 很重要”
3. **明确的违规风险**如果忽略此原则会出什么问题1 句话)
4. **尚未存在于规则中**:检查全部规则文本——包括以不同措辞表达的概念
## 匹配与裁决
对于每个候选原则,对照全部规则文本进行比较并给出裁决:
- **追加**:添加到现有规则文件的现有章节
- **修订**:现有规则内容不准确或不充分——提出修正建议
- **新章节**:在现有规则文件中添加新章节
- **新文件**:创建新的规则文件
- **已涵盖**:现有规则已充分涵盖(即使措辞不同)
- **过于具体**:应保留在技能层面
- **追加**:添加到现有规则文件的现有章节
- **修订**:现有规则内容不准确或不充分——提出修正建议
- **新章节**:在现有规则文件中添加新章节
- **新文件**:创建新的规则文件
- **已涵盖**:现有规则已充分涵盖(即使措辞不同)
- **过于具体**:应保留在技能层面
## 输出格式(每个候选原则)
@@ -112,9 +112,9 @@ bash ~/.claude/skills/rules-distill/scripts/scan-rules.sh
## 排除
- 规则中已存在的显而易见的原则
- 语言/框架特定知识(属于语言特定规则或技能)
- 代码示例和命令(属于技能)
- 规则中已存在的显而易见的原则
- 语言/框架特定知识(属于语言特定规则或技能)
- 代码示例和命令(属于技能)
````
#### 裁决参考

View File

@@ -22,14 +22,14 @@ origin: ECC
### 1. 密钥管理
#### 绝对不要这样做
#### FAIL: 绝对不要这样做
```typescript
const apiKey = "sk-proj-xxxxx" // Hardcoded secret
const dbPassword = "password123" // In source code
```
#### 始终这样做
#### PASS: 始终这样做
```typescript
const apiKey = process.env.OPENAI_API_KEY
@@ -114,7 +114,7 @@ function validateFileUpload(file: File) {
### 3. SQL 注入防护
#### 绝对不要拼接 SQL
#### FAIL: 绝对不要拼接 SQL
```typescript
// DANGEROUS - SQL Injection vulnerability
@@ -122,7 +122,7 @@ const query = `SELECT * FROM users WHERE email = '${userEmail}'`
await db.query(query)
```
#### 始终使用参数化查询
#### PASS: 始终使用参数化查询
```typescript
// Safe - parameterized query
@@ -150,10 +150,10 @@ await db.query(
#### JWT 令牌处理
```typescript
// WRONG: localStorage (vulnerable to XSS)
// FAIL: WRONG: localStorage (vulnerable to XSS)
localStorage.setItem('token', token)
// CORRECT: httpOnly cookies
// PASS: CORRECT: httpOnly cookies
res.setHeader('Set-Cookie',
`token=${token}; HttpOnly; Secure; SameSite=Strict; Max-Age=3600`)
```
@@ -323,11 +323,11 @@ app.use('/api/search', searchLimiter)
#### 日志记录
```typescript
// WRONG: Logging sensitive data
// FAIL: WRONG: Logging sensitive data
console.log('User login:', { email, password })
console.log('Payment:', { cardNumber, cvv })
// CORRECT: Redact sensitive data
// PASS: CORRECT: Redact sensitive data
console.log('User login:', { email, userId })
console.log('Payment:', { last4: card.last4, userId })
```
@@ -335,7 +335,7 @@ console.log('Payment:', { last4: card.last4, userId })
#### 错误消息
```typescript
// WRONG: Exposing internal details
// FAIL: WRONG: Exposing internal details
catch (error) {
return NextResponse.json(
{ error: error.message, stack: error.stack },
@@ -343,7 +343,7 @@ catch (error) {
)
}
// CORRECT: Generic error messages
// PASS: CORRECT: Generic error messages
catch (error) {
console.error('Internal error:', error)
return NextResponse.json(

View File

@@ -24,7 +24,7 @@
#### 最小权限原则
```yaml
# CORRECT: Minimal permissions
# PASS: CORRECT: Minimal permissions
iam_role:
permissions:
- s3:GetObject # Only read access
@@ -32,7 +32,7 @@ iam_role:
resources:
- arn:aws:s3:::my-bucket/* # Specific bucket only
# WRONG: Overly broad permissions
# FAIL: WRONG: Overly broad permissions
iam_role:
permissions:
- s3:* # All S3 actions
@@ -65,14 +65,14 @@ aws iam enable-mfa-device \
#### 云密钥管理器
```typescript
// CORRECT: Use cloud secrets manager
// PASS: CORRECT: Use cloud secrets manager
import { SecretsManager } from '@aws-sdk/client-secrets-manager';
const client = new SecretsManager({ region: 'us-east-1' });
const secret = await client.getSecretValue({ SecretId: 'prod/api-key' });
const apiKey = JSON.parse(secret.SecretString).key;
// WRONG: Hardcoded or in environment variables only
// FAIL: WRONG: Hardcoded or in environment variables only
const apiKey = process.env.API_KEY; // Not rotated, not audited
```
@@ -99,17 +99,17 @@ aws secretsmanager rotate-secret \
#### VPC 和防火墙配置
```terraform
# CORRECT: Restricted security group
# PASS: CORRECT: Restricted security group
resource "aws_security_group" "app" {
name = "app-sg"
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["10.0.0.0/16"] # Internal VPC only
}
egress {
from_port = 443
to_port = 443
@@ -118,7 +118,7 @@ resource "aws_security_group" "app" {
}
}
# WRONG: Open to the internet
# FAIL: WRONG: Open to the internet
resource "aws_security_group" "bad" {
ingress {
from_port = 0
@@ -142,7 +142,7 @@ resource "aws_security_group" "bad" {
#### CloudWatch/日志记录配置
```typescript
// CORRECT: Comprehensive logging
// PASS: CORRECT: Comprehensive logging
import { CloudWatchLogsClient, CreateLogStreamCommand } from '@aws-sdk/client-cloudwatch-logs';
const logSecurityEvent = async (event: SecurityEvent) => {
@@ -177,7 +177,7 @@ const logSecurityEvent = async (event: SecurityEvent) => {
#### 安全流水线配置
```yaml
# CORRECT: Secure GitHub Actions workflow
# PASS: CORRECT: Secure GitHub Actions workflow
name: Deploy
on:
@@ -189,18 +189,18 @@ jobs:
runs-on: ubuntu-latest
permissions:
contents: read # Minimal permissions
steps:
- uses: actions/checkout@v4
# Scan for secrets
- name: Secret scanning
uses: trufflesecurity/trufflehog@main
# Dependency audit
- name: Audit dependencies
run: npm audit --audit-level=high
# Use OIDC, not long-lived tokens
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
@@ -237,18 +237,18 @@ jobs:
#### Cloudflare 安全配置
```typescript
// CORRECT: Cloudflare Workers with security headers
// PASS: CORRECT: Cloudflare Workers with security headers
export default {
async fetch(request: Request): Promise<Response> {
const response = await fetch(request);
// Add security headers
const headers = new Headers(response.headers);
headers.set('X-Frame-Options', 'DENY');
headers.set('X-Content-Type-Options', 'nosniff');
headers.set('Referrer-Policy', 'strict-origin-when-cross-origin');
headers.set('Permissions-Policy', 'geolocation=(), microphone=()');
return new Response(response.body, {
status: response.status,
headers
@@ -281,17 +281,17 @@ export default {
#### 自动化备份
```terraform
# CORRECT: Automated RDS backups
# PASS: CORRECT: Automated RDS backups
resource "aws_db_instance" "main" {
allocated_storage = 20
engine = "postgres"
backup_retention_period = 30 # 30 days retention
backup_window = "03:00-04:00"
maintenance_window = "mon:04:00-mon:05:00"
enabled_cloudwatch_logs_exports = ["postgresql"]
deletion_protection = true # Prevent accidental deletion
}
```
@@ -327,10 +327,10 @@ resource "aws_db_instance" "main" {
### S3 存储桶暴露
```bash
# WRONG: Public bucket
# FAIL: WRONG: Public bucket
aws s3api put-bucket-acl --bucket my-bucket --acl public-read
# CORRECT: Private bucket with specific access
# PASS: CORRECT: Private bucket with specific access
aws s3api put-bucket-acl --bucket my-bucket --acl private
aws s3api put-bucket-policy --bucket my-bucket --policy file://policy.json
```
@@ -338,12 +338,12 @@ aws s3api put-bucket-policy --bucket my-bucket --policy file://policy.json
### RDS 公开访问
```terraform
# WRONG
# FAIL: WRONG
resource "aws_db_instance" "bad" {
publicly_accessible = true # NEVER do this!
}
# CORRECT
# PASS: CORRECT
resource "aws_db_instance" "good" {
publicly_accessible = false
vpc_security_group_ids = [aws_security_group.db.id]

View File

@@ -335,28 +335,28 @@ npm run test:coverage
## 应避免的常见测试错误
### 错误:测试实现细节
### FAIL: 错误:测试实现细节
```typescript
// Don't test internal state
expect(component.state.count).toBe(5)
```
### 正确:测试用户可见的行为
### PASS: 正确:测试用户可见的行为
```typescript
// Test what users see
expect(screen.getByText('Count: 5')).toBeInTheDocument()
```
### 错误:脆弱的定位器
### FAIL: 错误:脆弱的定位器
```typescript
// Breaks easily
await page.click('.css-class-xyz')
```
### 正确:语义化定位器
### PASS: 正确:语义化定位器
```typescript
// Resilient to changes
@@ -364,7 +364,7 @@ await page.click('button:has-text("Submit")')
await page.click('[data-testid="submit-button"]')
```
### 错误:没有测试隔离
### FAIL: 错误:没有测试隔离
```typescript
// Tests depend on each other
@@ -372,7 +372,7 @@ test('creates user', () => { /* ... */ })
test('updates same user', () => { /* depends on previous test */ })
```
### 正确:独立的测试
### PASS: 正确:独立的测试
```typescript
// Each test sets up its own data

View File

@@ -94,7 +94,7 @@ agents/
确认选择:
```
选定:安全工程师 + SEO专家
选定:安全工程师 + SEO专家
他们应该专注于什么任务?(描述任务)
```

View File

@@ -275,7 +275,7 @@ Return only valid JSON.""",
# Audio: every 50 words
{"type": "word", "value": 50}
# Audio: every 30 seconds
# Audio: every 30 seconds
{"type": "time", "value": 30}
# Visual: 5 frames every 2 seconds

View File

@@ -4,11 +4,11 @@
## 功能
* 🔄 **自动 OCR**:尝试多种 OCR 方法macOS Vision、EasyOCR、Tesseract
* 📄 **双语 PDF**:原始图像 + 专业英文翻译
* 🌍 **多语言支持**:支持中文及其他语言
* 📋 **专业格式**:适合官方签证申请
* 🚀 **完全自动化**:无需人工干预
* **自动 OCR**:尝试多种 OCR 方法macOS Vision、EasyOCR、Tesseract
* **双语 PDF**:原始图像 + 专业英文翻译
* **多语言支持**:支持中文及其他语言
* **专业格式**:适合官方签证申请
* **完全自动化**:无需人工干预
## 支持的文件类型
@@ -80,11 +80,11 @@ pip install pytesseract
## 完美适用于
* 🇦🇺 澳大利亚签证申请
* 🇺🇸 美国签证申请
* 🇨🇦 加拿大签证申请
* 🇬🇧 英国签证申请
* 🇪🇺 欧盟签证申请
* 澳大利亚签证申请
* 美国签证申请
* 加拿大签证申请
* 英国签证申请
* 欧盟签证申请
## 许可证