@critiq/rules 0.0.1
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 +169 -0
- package/catalog.yaml +599 -0
- package/package.json +21 -0
- package/rules/shared/security.insecure-http-transport.rule.yaml +42 -0
- package/rules/shared/security.no-command-execution-with-request-input.rule.yaml +42 -0
- package/rules/shared/security.no-hardcoded-credentials.rule.yaml +42 -0
- package/rules/shared/security.no-request-path-file-read.rule.yaml +42 -0
- package/rules/shared/security.no-sensitive-data-in-logs-and-telemetry.rule.yaml +44 -0
- package/rules/shared/security.no-sql-interpolation.rule.yaml +42 -0
- package/rules/shared/security.tls-verification-disabled.rule.yaml +42 -0
- package/rules/shared/security.unsafe-deserialization.rule.yaml +41 -0
- package/rules/shared/security.weak-hash-algorithm.rule.yaml +41 -0
- package/rules/typescript/ts.config.no-process-env-outside-config.rule.yaml +37 -0
- package/rules/typescript/ts.correctness.blocking-call-in-async-flow.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.constant-condition.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.implicit-undefined-return.rule.yaml +34 -0
- package/rules/typescript/ts.correctness.incorrect-boolean-logic.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.missing-await-on-async-call.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.missing-default-dispatch.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.missing-timeout-on-external-call.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.nested-property-access-without-check.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.off-by-one-loop-boundary.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.optional-value-without-fallback.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.possible-null-dereference.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.shared-state-race.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.unchecked-map-key-access.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.unhandled-async-error.rule.yaml +35 -0
- package/rules/typescript/ts.correctness.unreachable-statement.rule.yaml +40 -0
- package/rules/typescript/ts.logging.no-console-error.rule.yaml +34 -0
- package/rules/typescript/ts.logging.no-console-log.rule.yaml +34 -0
- package/rules/typescript/ts.next.no-server-client-boundary-leaks.rule.yaml +36 -0
- package/rules/typescript/ts.performance.inefficient-data-structure-usage.rule.yaml +35 -0
- package/rules/typescript/ts.performance.large-payload-without-streaming.rule.yaml +35 -0
- package/rules/typescript/ts.performance.missing-batch-operations.rule.yaml +35 -0
- package/rules/typescript/ts.performance.nested-loops-hot-path.rule.yaml +35 -0
- package/rules/typescript/ts.performance.repeated-expensive-computation.rule.yaml +35 -0
- package/rules/typescript/ts.performance.repeated-io-in-loop.rule.yaml +35 -0
- package/rules/typescript/ts.performance.retained-large-object.rule.yaml +35 -0
- package/rules/typescript/ts.performance.sequential-async-calls.rule.yaml +35 -0
- package/rules/typescript/ts.performance.unbounded-growth-memory-leak.rule.yaml +35 -0
- package/rules/typescript/ts.performance.unnecessary-rerenders-from-state-misuse.rule.yaml +35 -0
- package/rules/typescript/ts.quality.deep-nesting.rule.yaml +35 -0
- package/rules/typescript/ts.quality.duplicate-code-block.rule.yaml +35 -0
- package/rules/typescript/ts.quality.function-too-large-or-complex.rule.yaml +35 -0
- package/rules/typescript/ts.quality.hardcoded-configuration-values.rule.yaml +35 -0
- package/rules/typescript/ts.quality.logic-change-without-test-updates.rule.yaml +36 -0
- package/rules/typescript/ts.quality.magic-numbers-or-strings.rule.yaml +35 -0
- package/rules/typescript/ts.quality.missing-error-context.rule.yaml +35 -0
- package/rules/typescript/ts.quality.missing-tests-for-critical-logic.rule.yaml +35 -0
- package/rules/typescript/ts.quality.swallowed-error.rule.yaml +35 -0
- package/rules/typescript/ts.quality.tight-module-coupling.rule.yaml +35 -0
- package/rules/typescript/ts.random.no-math-random-in-core.rule.yaml +37 -0
- package/rules/typescript/ts.react.no-cascaded-effect-fetches.rule.yaml +37 -0
- package/rules/typescript/ts.runtime.no-debugger-statement.rule.yaml +29 -0
- package/rules/typescript/ts.security.bind-to-all-interfaces.rule.yaml +36 -0
- package/rules/typescript/ts.security.browser-token-storage.rule.yaml +37 -0
- package/rules/typescript/ts.security.dangerous-insert-html.rule.yaml +36 -0
- package/rules/typescript/ts.security.dangerously-set-inner-html.rule.yaml +38 -0
- package/rules/typescript/ts.security.datadog-browser-track-user-interactions.rule.yaml +37 -0
- package/rules/typescript/ts.security.debug-mode-enabled.rule.yaml +38 -0
- package/rules/typescript/ts.security.dynamodb-query-injection.rule.yaml +36 -0
- package/rules/typescript/ts.security.exposed-directory-listing.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-cookie-missing-http-only.rule.yaml +36 -0
- package/rules/typescript/ts.security.express-default-cookie-config.rule.yaml +39 -0
- package/rules/typescript/ts.security.express-default-session-config.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-insecure-cookie.rule.yaml +36 -0
- package/rules/typescript/ts.security.express-missing-helmet.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-nosql-injection.rule.yaml +36 -0
- package/rules/typescript/ts.security.express-permissive-cookie-config.rule.yaml +38 -0
- package/rules/typescript/ts.security.express-reduce-fingerprint.rule.yaml +37 -0
- package/rules/typescript/ts.security.express-static-assets-after-session.rule.yaml +37 -0
- package/rules/typescript/ts.security.external-file-upload.rule.yaml +36 -0
- package/rules/typescript/ts.security.file-generation.rule.yaml +36 -0
- package/rules/typescript/ts.security.format-string-using-user-input.rule.yaml +36 -0
- package/rules/typescript/ts.security.frontend-only-authorization.rule.yaml +35 -0
- package/rules/typescript/ts.security.handlebars-no-escape.rule.yaml +38 -0
- package/rules/typescript/ts.security.hardcoded-auth-secret.rule.yaml +37 -0
- package/rules/typescript/ts.security.import-using-user-input.rule.yaml +36 -0
- package/rules/typescript/ts.security.information-leakage.rule.yaml +38 -0
- package/rules/typescript/ts.security.insecure-allow-origin.rule.yaml +36 -0
- package/rules/typescript/ts.security.insecure-auth-cookie-flags.rule.yaml +37 -0
- package/rules/typescript/ts.security.insecure-password-hash-configuration.rule.yaml +37 -0
- package/rules/typescript/ts.security.insecure-websocket-transport.rule.yaml +37 -0
- package/rules/typescript/ts.security.insufficiently-random-values.rule.yaml +36 -0
- package/rules/typescript/ts.security.jwt-not-revoked.rule.yaml +37 -0
- package/rules/typescript/ts.security.jwt-sensitive-claims.rule.yaml +37 -0
- package/rules/typescript/ts.security.manual-html-sanitization.rule.yaml +37 -0
- package/rules/typescript/ts.security.missing-authorization-before-sensitive-action.rule.yaml +35 -0
- package/rules/typescript/ts.security.missing-integrity-check.rule.yaml +36 -0
- package/rules/typescript/ts.security.missing-message-origin-check.rule.yaml +36 -0
- package/rules/typescript/ts.security.missing-ownership-validation.rule.yaml +35 -0
- package/rules/typescript/ts.security.missing-request-timeout-or-retry.rule.yaml +35 -0
- package/rules/typescript/ts.security.no-dynamic-execution.rule.yaml +34 -0
- package/rules/typescript/ts.security.no-innerhtml-assignment.rule.yaml +36 -0
- package/rules/typescript/ts.security.non-literal-fs-filename.rule.yaml +36 -0
- package/rules/typescript/ts.security.observable-timing-discrepancy.rule.yaml +37 -0
- package/rules/typescript/ts.security.open-redirect.rule.yaml +37 -0
- package/rules/typescript/ts.security.permissive-allow-origin.rule.yaml +36 -0
- package/rules/typescript/ts.security.permissive-file-permissions.rule.yaml +37 -0
- package/rules/typescript/ts.security.postmessage-wildcard-origin.rule.yaml +36 -0
- package/rules/typescript/ts.security.predictable-token-generation.rule.yaml +36 -0
- package/rules/typescript/ts.security.raw-html-using-user-input.rule.yaml +37 -0
- package/rules/typescript/ts.security.sensitive-data-egress.rule.yaml +36 -0
- package/rules/typescript/ts.security.sensitive-data-in-exception.rule.yaml +37 -0
- package/rules/typescript/ts.security.sensitive-data-written-to-file.rule.yaml +37 -0
- package/rules/typescript/ts.security.ssrf.rule.yaml +34 -0
- package/rules/typescript/ts.security.token-or-session-not-validated.rule.yaml +35 -0
- package/rules/typescript/ts.security.ui-redress.rule.yaml +37 -0
- package/rules/typescript/ts.security.unsanitized-http-response.rule.yaml +36 -0
- package/rules/typescript/ts.security.unvalidated-external-input.rule.yaml +35 -0
- package/rules/typescript/ts.security.user-controlled-sendfile.rule.yaml +36 -0
- package/rules/typescript/ts.security.user-controlled-view-render.rule.yaml +36 -0
- package/rules/typescript/ts.security.weak-cipher-or-mode.rule.yaml +35 -0
- package/rules/typescript/ts.security.weak-key-strength.rule.yaml +36 -0
- package/rules/typescript/ts.security.weak-tls-version.rule.yaml +36 -0
- package/src/index.d.ts +1 -0
- package/src/index.js +5 -0
- package/src/index.js.map +1 -0
- package/src/lib/rules-package.d.ts +3 -0
- package/src/lib/rules-package.js +16 -0
- package/src/lib/rules-package.js.map +1 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.no-hardcoded-credentials
|
|
5
|
+
title: Hardcoded API keys or credentials
|
|
6
|
+
summary: Source files should not embed credential-like string literals.
|
|
7
|
+
rationale: Hardcoded credentials are difficult to rotate and are easily leaked through source control.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- secrets
|
|
11
|
+
- credentials
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: file
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
- go
|
|
20
|
+
- python
|
|
21
|
+
- java
|
|
22
|
+
- php
|
|
23
|
+
- ruby
|
|
24
|
+
- rust
|
|
25
|
+
match:
|
|
26
|
+
fact:
|
|
27
|
+
kind: security.hardcoded-credentials
|
|
28
|
+
bind: credential
|
|
29
|
+
emit:
|
|
30
|
+
finding:
|
|
31
|
+
category: security.secrets
|
|
32
|
+
severity: critical
|
|
33
|
+
confidence: 0.95
|
|
34
|
+
tags:
|
|
35
|
+
- security
|
|
36
|
+
- secrets
|
|
37
|
+
- credentials
|
|
38
|
+
message:
|
|
39
|
+
title: Avoid hardcoded credentials in `${captures.credential.text}`
|
|
40
|
+
summary: "`${captures.credential.text}` appears to embed a credential-like literal in source code."
|
|
41
|
+
remediation:
|
|
42
|
+
summary: Move the secret to a secure runtime secret store or environment-backed config path.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.no-request-path-file-read
|
|
5
|
+
title: Path traversal via user input
|
|
6
|
+
summary: File access calls must not use request-controlled paths directly.
|
|
7
|
+
rationale: User-controlled paths can escape the intended directory and expose sensitive files.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- filesystem
|
|
11
|
+
- path-traversal
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
- go
|
|
20
|
+
- python
|
|
21
|
+
- java
|
|
22
|
+
- php
|
|
23
|
+
- ruby
|
|
24
|
+
- rust
|
|
25
|
+
match:
|
|
26
|
+
fact:
|
|
27
|
+
kind: security.request-path-file-read
|
|
28
|
+
bind: fileRead
|
|
29
|
+
emit:
|
|
30
|
+
finding:
|
|
31
|
+
category: security.filesystem
|
|
32
|
+
severity: high
|
|
33
|
+
confidence: 0.85
|
|
34
|
+
tags:
|
|
35
|
+
- security
|
|
36
|
+
- filesystem
|
|
37
|
+
- path-traversal
|
|
38
|
+
message:
|
|
39
|
+
title: Avoid request-controlled file access in `${captures.fileRead.text}`
|
|
40
|
+
summary: "`${captures.fileRead.text}` reads from a path derived from request data without an allowlist or boundary check."
|
|
41
|
+
remediation:
|
|
42
|
+
summary: Resolve the path against a trusted base directory and reject values that escape it.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.no-sensitive-data-in-logs-and-telemetry
|
|
5
|
+
title: Avoid sensitive data in logs and telemetry
|
|
6
|
+
summary: Sensitive fields should not be sent to logging, tracing, or analytics sinks.
|
|
7
|
+
rationale: Observability payloads often leave the service boundary and can expose secrets, account identifiers, or personal data if they carry raw request or user fields.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- privacy
|
|
11
|
+
- logging
|
|
12
|
+
- telemetry
|
|
13
|
+
- rules-catalog
|
|
14
|
+
stability: stable
|
|
15
|
+
appliesTo: function
|
|
16
|
+
scope:
|
|
17
|
+
languages:
|
|
18
|
+
- typescript
|
|
19
|
+
- javascript
|
|
20
|
+
- go
|
|
21
|
+
- python
|
|
22
|
+
- java
|
|
23
|
+
- php
|
|
24
|
+
- ruby
|
|
25
|
+
- rust
|
|
26
|
+
match:
|
|
27
|
+
fact:
|
|
28
|
+
kind: security.sensitive-data-in-logs-and-telemetry
|
|
29
|
+
bind: issue
|
|
30
|
+
emit:
|
|
31
|
+
finding:
|
|
32
|
+
category: security.privacy
|
|
33
|
+
severity: high
|
|
34
|
+
confidence: 0.85
|
|
35
|
+
tags:
|
|
36
|
+
- security
|
|
37
|
+
- privacy
|
|
38
|
+
- logging
|
|
39
|
+
- telemetry
|
|
40
|
+
message:
|
|
41
|
+
title: Remove sensitive data from logs and telemetry
|
|
42
|
+
summary: "`${captures.issue.text}` reaches a logging or telemetry sink with sensitive data."
|
|
43
|
+
remediation:
|
|
44
|
+
summary: Redact, hash, or drop the sensitive field before it reaches the sink.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.no-sql-interpolation
|
|
5
|
+
title: Avoid raw or interpolated SQL
|
|
6
|
+
summary: Database query sinks must not receive request-driven or dynamically interpolated SQL text.
|
|
7
|
+
rationale: Raw or interpolated SQL can let attackers control query structure when values are not passed separately.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- sql
|
|
11
|
+
- injection
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
- go
|
|
20
|
+
- python
|
|
21
|
+
- java
|
|
22
|
+
- php
|
|
23
|
+
- ruby
|
|
24
|
+
- rust
|
|
25
|
+
match:
|
|
26
|
+
fact:
|
|
27
|
+
kind: security.sql-interpolation
|
|
28
|
+
bind: queryCall
|
|
29
|
+
emit:
|
|
30
|
+
finding:
|
|
31
|
+
category: security.injection
|
|
32
|
+
severity: high
|
|
33
|
+
confidence: 0.95
|
|
34
|
+
tags:
|
|
35
|
+
- security
|
|
36
|
+
- sql
|
|
37
|
+
- injection
|
|
38
|
+
message:
|
|
39
|
+
title: Avoid interpolated SQL in `${captures.queryCall.text}`
|
|
40
|
+
summary: "`${captures.queryCall.text}` builds or forwards SQL text directly into a raw query sink."
|
|
41
|
+
remediation:
|
|
42
|
+
summary: Use prepared statements, placeholder parameters, or a typed query builder instead of executing raw SQL text.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.tls-verification-disabled
|
|
5
|
+
title: TLS verification disabled
|
|
6
|
+
summary: Transport clients should not disable certificate verification.
|
|
7
|
+
rationale: Trust-all TLS settings accept any certificate and undermine transport security.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- transport
|
|
11
|
+
- tls
|
|
12
|
+
- rules-catalog
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
- go
|
|
20
|
+
- python
|
|
21
|
+
- java
|
|
22
|
+
- php
|
|
23
|
+
- ruby
|
|
24
|
+
- rust
|
|
25
|
+
match:
|
|
26
|
+
fact:
|
|
27
|
+
kind: security.tls-verification-disabled
|
|
28
|
+
bind: issue
|
|
29
|
+
emit:
|
|
30
|
+
finding:
|
|
31
|
+
category: security.transport
|
|
32
|
+
severity: high
|
|
33
|
+
confidence: 0.9
|
|
34
|
+
tags:
|
|
35
|
+
- security
|
|
36
|
+
- transport
|
|
37
|
+
- tls
|
|
38
|
+
message:
|
|
39
|
+
title: TLS verification disabled in `${captures.issue.text}`
|
|
40
|
+
summary: "`${captures.issue.text}` disables certificate verification or trust validation."
|
|
41
|
+
remediation:
|
|
42
|
+
summary: Use trusted certificate validation and remove trust-all overrides outside local development.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.unsafe-deserialization
|
|
5
|
+
title: Protect deserialization trust boundaries
|
|
6
|
+
summary: Deserializers should not consume untrusted payloads directly across a trust boundary.
|
|
7
|
+
rationale: Deserializing untrusted payloads can let attacker-controlled data reshape parser state, object graphs, or downstream runtime behavior.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- deserialization
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-sec-028
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
- go
|
|
20
|
+
- python
|
|
21
|
+
- java
|
|
22
|
+
- php
|
|
23
|
+
- ruby
|
|
24
|
+
- rust
|
|
25
|
+
match:
|
|
26
|
+
fact:
|
|
27
|
+
kind: security.unsafe-deserialization
|
|
28
|
+
bind: issue
|
|
29
|
+
emit:
|
|
30
|
+
finding:
|
|
31
|
+
category: security.deserialization
|
|
32
|
+
severity: high
|
|
33
|
+
confidence: 0.85
|
|
34
|
+
tags:
|
|
35
|
+
- security
|
|
36
|
+
- deserialization
|
|
37
|
+
message:
|
|
38
|
+
title: Constrain the trust boundary before `${captures.issue.text}`
|
|
39
|
+
summary: "`${captures.issue.text}` deserializes an untrusted payload across a trust boundary."
|
|
40
|
+
remediation:
|
|
41
|
+
summary: Deserialize only from trusted producers, or validate and constrain the payload shape before crossing the deserialization boundary.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: security.weak-hash-algorithm
|
|
5
|
+
title: Avoid weak hash algorithms
|
|
6
|
+
summary: Cryptographic hashing should use modern, collision-resistant algorithms.
|
|
7
|
+
rationale: Weak digests such as MD5 and SHA-1 are vulnerable to collisions and should not be used for security-sensitive hashing.
|
|
8
|
+
tags:
|
|
9
|
+
- security
|
|
10
|
+
- crypto
|
|
11
|
+
- rules-catalog
|
|
12
|
+
stability: stable
|
|
13
|
+
appliesTo: block
|
|
14
|
+
scope:
|
|
15
|
+
languages:
|
|
16
|
+
- typescript
|
|
17
|
+
- javascript
|
|
18
|
+
- go
|
|
19
|
+
- python
|
|
20
|
+
- java
|
|
21
|
+
- php
|
|
22
|
+
- ruby
|
|
23
|
+
- rust
|
|
24
|
+
match:
|
|
25
|
+
fact:
|
|
26
|
+
kind: security.weak-hash-algorithm
|
|
27
|
+
bind: issue
|
|
28
|
+
emit:
|
|
29
|
+
finding:
|
|
30
|
+
category: security.secrets
|
|
31
|
+
severity: high
|
|
32
|
+
confidence: 0.9
|
|
33
|
+
tags:
|
|
34
|
+
- security
|
|
35
|
+
- crypto
|
|
36
|
+
- hash
|
|
37
|
+
message:
|
|
38
|
+
title: Avoid weak hash algorithms
|
|
39
|
+
summary: "`${captures.issue.text}` uses a weak hash algorithm."
|
|
40
|
+
remediation:
|
|
41
|
+
summary: Use SHA-256, SHA-384, SHA-512, or a stronger approved hashing primitive instead.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.config.no-process-env-outside-config
|
|
5
|
+
title: Avoid direct `process.env` access outside config
|
|
6
|
+
summary: Keep environment variable access inside config modules.
|
|
7
|
+
rationale: Centralized config makes environment handling predictable and testable.
|
|
8
|
+
tags:
|
|
9
|
+
- config
|
|
10
|
+
- rules-catalog
|
|
11
|
+
scope:
|
|
12
|
+
languages:
|
|
13
|
+
- typescript
|
|
14
|
+
paths:
|
|
15
|
+
exclude:
|
|
16
|
+
- "**/config/**"
|
|
17
|
+
match:
|
|
18
|
+
node:
|
|
19
|
+
kind: MemberExpression
|
|
20
|
+
bind: envAccess
|
|
21
|
+
where:
|
|
22
|
+
- path: object.object.text
|
|
23
|
+
equals: process
|
|
24
|
+
- path: object.property.text
|
|
25
|
+
equals: env
|
|
26
|
+
emit:
|
|
27
|
+
finding:
|
|
28
|
+
category: maintainability
|
|
29
|
+
severity: medium
|
|
30
|
+
confidence: high
|
|
31
|
+
tags:
|
|
32
|
+
- config
|
|
33
|
+
message:
|
|
34
|
+
title: Avoid `${captures.envAccess.text}`
|
|
35
|
+
summary: Keep `${captures.envAccess.text}` access inside config modules.
|
|
36
|
+
remediation:
|
|
37
|
+
summary: Read the environment value in a config module and inject it where needed.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.blocking-call-in-async-flow
|
|
5
|
+
title: Blocking call inside async flow
|
|
6
|
+
summary: Async functions should not call synchronous blocking APIs on the hot path.
|
|
7
|
+
rationale: Blocking sync APIs stall the event loop and erase the throughput benefits of async control flow.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- async
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-013
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: async.blocking-call-in-async-flow
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.async
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.75
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- async
|
|
31
|
+
message:
|
|
32
|
+
title: Avoid blocking sync calls in async flows
|
|
33
|
+
summary: "`${captures.issue.text}` uses a blocking sync API inside an async function."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Replace the sync API with its asynchronous equivalent or move the blocking work out of the async request path.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.constant-condition
|
|
5
|
+
title: Always-true or always-false condition
|
|
6
|
+
summary: Flow-control conditions should not resolve to a constant boolean value.
|
|
7
|
+
rationale: Constant conditions hide dead branches and usually signal leftover debug code or a mistaken comparison.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- logic
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-006
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: control-flow.constant-condition
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.logic
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.95
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- logic
|
|
31
|
+
message:
|
|
32
|
+
title: Review constant condition
|
|
33
|
+
summary: "`${captures.issue.text}` always resolves to the same boolean value."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Replace the constant predicate with a real runtime check or remove the dead branch.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.implicit-undefined-return
|
|
5
|
+
title: Implicit undefined return in function
|
|
6
|
+
summary: Functions that return a value on some paths must not fall through implicitly.
|
|
7
|
+
rationale: Mixed value-return and implicit-fallthrough paths are a common source of undefined behavior.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- control-flow
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-005
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: function
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: control-flow.implicit-undefined-return
|
|
22
|
+
emit:
|
|
23
|
+
finding:
|
|
24
|
+
category: correctness.control-flow
|
|
25
|
+
severity: medium
|
|
26
|
+
confidence: 0.9
|
|
27
|
+
tags:
|
|
28
|
+
- correctness
|
|
29
|
+
- control-flow
|
|
30
|
+
message:
|
|
31
|
+
title: Avoid implicit undefined return
|
|
32
|
+
summary: This function returns a value on some paths but falls through without returning on others.
|
|
33
|
+
remediation:
|
|
34
|
+
summary: Return a value on every reachable path or make the function consistently void.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.incorrect-boolean-logic
|
|
5
|
+
title: Incorrect boolean logic (AND/OR misuse)
|
|
6
|
+
summary: Comparison chains on the same value must use the boolean operator that matches the intended logic.
|
|
7
|
+
rationale: Using `&&` for mutually exclusive equality checks or `||` for inequality chains produces conditions that can never behave as intended.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- logic
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-008
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: control-flow.incorrect-boolean-logic
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.logic
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- logic
|
|
31
|
+
message:
|
|
32
|
+
title: Review boolean comparison logic
|
|
33
|
+
summary: "`${captures.issue.text}` uses an AND/OR comparison chain that cannot behave as intended."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Use `||` for equality alternatives or `&&` for inequality exclusions, depending on the intended condition.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.missing-await-on-async-call
|
|
5
|
+
title: Missing await on async call
|
|
6
|
+
summary: Async functions should not drop direct async calls without awaiting them.
|
|
7
|
+
rationale: Unawaited async work in an async function often indicates a missed dependency or a promise that can reject outside the intended control flow.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- async
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-011
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: async.missing-await
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.async
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- async
|
|
31
|
+
message:
|
|
32
|
+
title: Await direct async work
|
|
33
|
+
summary: "`${captures.issue.text}` starts async work without `await`."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Await the call, return the promise explicitly, or document a deliberate fire-and-forget path outside the async flow.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.missing-default-dispatch
|
|
5
|
+
title: Missing default case in switch or conditional dispatch
|
|
6
|
+
summary: Dispatch constructs should include an explicit default or final else path.
|
|
7
|
+
rationale: Default handling makes control-flow intent explicit and avoids silent fallthrough for unhandled values.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- control-flow
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-007
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: control-flow.missing-default-dispatch
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.control-flow
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.85
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- control-flow
|
|
31
|
+
message:
|
|
32
|
+
title: Add an explicit default dispatch path
|
|
33
|
+
summary: "Review `${captures.issue.text}` and add a `default` case or final `else`."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Handle the fallback branch explicitly so unexpected values do not rely on implicit behavior.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.missing-timeout-on-external-call
|
|
5
|
+
title: Missing timeout on external call
|
|
6
|
+
summary: External HTTP calls should declare timeout or cancellation behavior.
|
|
7
|
+
rationale: Network calls without explicit timeouts can hang indefinitely and make retry or fallback behavior unreliable.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- resilience
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-014
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: resilience.missing-timeout-on-external-call
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.resilience
|
|
26
|
+
severity: high
|
|
27
|
+
confidence: 0.9
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- resilience
|
|
31
|
+
message:
|
|
32
|
+
title: Configure timeouts on external calls
|
|
33
|
+
summary: "`${captures.issue.text}` performs an external call without explicit timeout or cancellation settings."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Add a timeout-bearing config object, such as `signal` for `fetch` or `timeout` for axios.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.nested-property-access-without-check
|
|
5
|
+
title: Nested property access without existence check
|
|
6
|
+
summary: Deep property chains derived from external input should verify intermediate values before access.
|
|
7
|
+
rationale: Multi-hop access into request or payload objects is brittle when any segment can be absent, renamed, or malformed.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- "null"
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-002
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: data-flow.nested-property-access-without-check
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.null
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.8
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- "null"
|
|
31
|
+
message:
|
|
32
|
+
title: Check nested external-input paths before use
|
|
33
|
+
summary: "`${captures.issue.text}` walks a deep property chain without checking that each segment exists."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Add guards for the intermediate objects or switch the chain to explicit optional access with a fallback.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
apiVersion: critiq.dev/v1alpha1
|
|
2
|
+
kind: Rule
|
|
3
|
+
metadata:
|
|
4
|
+
id: ts.correctness.off-by-one-loop-boundary
|
|
5
|
+
title: Off-by-one error in loop boundaries
|
|
6
|
+
summary: Index-based loops should not skip the first element or iterate one step past the collection boundary.
|
|
7
|
+
rationale: Off-by-one loop conditions frequently cause undefined reads, missed work, or stale guard logic around array bounds.
|
|
8
|
+
tags:
|
|
9
|
+
- correctness
|
|
10
|
+
- logic
|
|
11
|
+
- rules-catalog
|
|
12
|
+
- crq-cor-009
|
|
13
|
+
stability: stable
|
|
14
|
+
appliesTo: block
|
|
15
|
+
scope:
|
|
16
|
+
languages:
|
|
17
|
+
- typescript
|
|
18
|
+
- javascript
|
|
19
|
+
match:
|
|
20
|
+
fact:
|
|
21
|
+
kind: control-flow.off-by-one-loop-boundary
|
|
22
|
+
bind: issue
|
|
23
|
+
emit:
|
|
24
|
+
finding:
|
|
25
|
+
category: correctness.logic
|
|
26
|
+
severity: medium
|
|
27
|
+
confidence: 0.85
|
|
28
|
+
tags:
|
|
29
|
+
- correctness
|
|
30
|
+
- logic
|
|
31
|
+
message:
|
|
32
|
+
title: Review loop boundary condition
|
|
33
|
+
summary: "`${captures.issue.text}` likely skips or overruns one loop iteration."
|
|
34
|
+
remediation:
|
|
35
|
+
summary: Use `< collection.length` for ascending loops and `>= 0` for descending loops that start at `length - 1`.
|