# rules/eslint/no-secret-value.eslint.rule.ts

> 49 lines of code and 9 definitions.

Tree: GovLab Extension Host
Language: typescript
Canonical: https://banes-lab.com/anatomy/governance#file-governance-rules-eslint-no-secret-value-eslint-rule-ts
Source text: https://banes-lab.com/source/governance/rules/eslint/no-secret-value.eslint.rule.ts.txt

Listed in [rules/eslint](https://banes-lab.com/api/source/governance/rules/eslint.md), after [rules/eslint/no-runtime-absent-member.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/no-runtime-absent-member.eslint.rule.ts.md) and before [rules/eslint/no-string-literal-ids.eslint.rule.ts](https://banes-lab.com/source/governance/rules/eslint/no-string-literal-ids.eslint.rule.ts.md).

## Definitions

- `quasiTexts` (lexical_declaration, line 10)
- `create` (method_definition, line 20, exported)
- `DETECTORS` (lexical_declaration, line 8)
- `firstKind` (lexical_declaration, line 14)
- `[kind]` (lexical_declaration, line 15)
- `literal` (method_definition, line 22, exported)
- `text` (lexical_declaration, line 23, exported)
- `templateLiteral` (method_definition, line 29, exported)
- `kind` (lexical_declaration, line 30, exported)

## Contained in

- [rules/eslint](https://banes-lab.com/anatomy/governance/folder-governance-rules-eslint.md)

## Uses

- [shared/factories/listener.factory.ts](https://banes-lab.com/source/governance/shared/factories/listener.factory.ts.md)
- [shared/selectors/syntax.selector.ts](https://banes-lab.com/source/governance/shared/selectors/syntax.selector.ts.md)

## Enforces

- [Secrets Management](https://banes-lab.com/records/architecture/secrets-management.md)

## Detector for

- [Hardcoded Configuration](https://banes-lab.com/records/architecture/hardcoded-configuration.md)
- [Secret Sprawl](https://banes-lab.com/records/architecture/secret-sprawl.md)

## Linked from

- [shared/factories](https://banes-lab.com/anatomy/governance/folder-governance-shared-factories.md)
- [shared/selectors](https://banes-lab.com/anatomy/governance/folder-governance-shared-selectors.md)

## Source

```typescript
import type { LocalRule, RuleContext, RuleListener } from "../../types/rule.types.ts";
import { detectedKinds, loadDetectors } from "@ssot/secrets";
import { literalString, nodesAt, recordAt, stringIn } from "../../shared/selectors/syntax.selector.ts";
import type { AstNode } from "../../types/syntax.types.ts";
import { defineCheck } from "@govlab/context/check";
import { listener } from "../../shared/factories/listener.factory.ts";

const DETECTORS = await loadDetectors();

const quasiTexts = function quasiTexts(view: AstNode): readonly string[] {
    return nodesAt(view, "quasis").map((part) => stringIn(recordAt(part, "value"), "cooked"));
};

const firstKind = function firstKind(texts: readonly string[]): string | undefined {
    const [kind] = texts.flatMap((text) => detectedKinds(text, DETECTORS));
    return kind;
};

export default {
    create(context: RuleContext): RuleListener {
        return listener({
            literal(view, node) {
                const text = literalString(view);
                const kind = text === null ? undefined : firstKind([text]);
                if (kind !== undefined) {
                    context.report({ data: { kind }, messageId: "secretValue", node });
                }
            },
            templateLiteral(view, node) {
                const kind = firstKind(quasiTexts(view));
                if (kind !== undefined) {
                    context.report({ data: { kind }, messageId: "secretValue", node });
                }
            },
        });
    },
    meta: {
        docs: {
            checks: defineCheck({
                detects: ["architecture:hardcoded-configuration", "architecture:secret-sprawl"],
                enforces: ["architecture:secrets-management"],
            }),
            description:
                "A value with the shape of a secret or a server fact is never written in source. The rule runs every string through the detectors the secret store registers, one per kind: vendor tokens, signed web tokens, bearer headers, private keys, SSH keys, database URLs, URLs that carry a user and a password, and IP addresses. A finding names the kind and never the value.",
        },
        messages: {
            secretValue:
                "This string has the shape of a {{kind}} value. Move it into the secret store under a key its schema declares, and read it through the store's typed accessor.",
        },
        schema: [],
        type: "problem",
    },
} satisfies LocalRule;
```
