@saleor/eslint-plugin-saleor-app
Version:
ESLint plugin for Saleor Apps
228 lines (166 loc) • 5.67 kB
Markdown
# Saleor App — ESLint plugin
ESLint plugin with rules for Saleor Apps
[](https://www.npmjs.com/package/@saleor/eslint-plugin-saleor-app)
## Get started
Saleor App ESLint plugin requires TypeScript ESLint Parser to be installed and configured in your app.
If you're using Next.js it's already included in the default [`eslint-config-next` config](https://github.com/vercel/next.js/blob/canary/packages/eslint-config-next/index.js#L111)
### 1. Install
Add the plugin to your dependencies
```
pnpm i -D /eslint-plugin-saleor-app
```
or
```
npm i --save-dev /eslint-plugin-saleor-app
```
> **Note**
> If you're not already using [`typescript-eslint`](https://typescript-eslint.io/) remember to install it as additional package:
>
> ```
> pnpm i -D -eslint/parser
> ```
>
> or
>
> ```
> npm i --save-dev -eslint/parser
> ```
### 2. Configure ESLint
You can either use recommended configuration or configure each rule manually.
#### Flat config
##### Recommended configuration
```ts
import saleorPlugin from "@saleor/eslint-plugin-saleor-app";
export default [saleorPlugin.configs["flat/recommended"]];
```
##### Manual configuration
```ts
import saleorPlugin from "@saleor/eslint-plugin-saleor-app";
export default [
{
plugins: { "@saleor/saleor-app": saleorPlugin },
rules: { "@saleor/saleor-app/logger-leak": "error" },
},
];
```
#### Legacy config
##### Recommended configuration
```json
{
"extends": ["plugin:@saleor/saleor-app/recommended"]
}
```
##### Manual configuration
Add the plugin to your ESLint config:
```json
{
"plugins": ["@saleor/saleor-app"]
}
```
Then configure the rules:
```json
{
"rules": {
"@saleor/saleor-app/logger-leak": "error"
}
}
```
## Rules
> **Warning**
> Remember to prefix the rules with `/saleor-app/<rule_name>`
### `logger-leak`
Checks if `logger.` usage accidentaly leaks potentially PII by passing a shorthand value, which is an object or an array
#### ❌ Not allowed
```ts
const myData = { apiKey: "super-secret-key" };
logger.info({ myData }, "Some log message");
// Error: Potential PII leak: object shorthand property
// used with object value inside logger arguments.
// Pass only specific fields from the object to the logger.
```
```ts
const apiKeys = ["super-secret-key"];
logger.info({ apiKeys }, "Some log message");
// Error: Potential PII leak: object shorthand property
// used with array value inside logger arguments.
// Please use `redactLogArray` method.
```
> **Info**
> If you need an example of `redactLogArray` method take a look at an implementation in [saleor-app-payment-template](https://github.com/saleor/saleor-app-payment-template/blob/canary/src/lib/logger.ts#L90).
```ts
const myData = "some data" as any;
logger.info({ myData }, "Some log message");
// Error: Potential PII leak: object shorthand property
// used with unknown value inside logger arguments.
// Please use only known values.
```
#### ✅ Allowed
```ts
const myData = { apiKey: "super-secret-key", userName: "John" };
const { userName } = myData;
// Note that `userName` is a primitive value (string), so it will be allowed
logger.info({ userName }, "Some log message");
```
or
```ts
import { obfuscateObject } from "./utils";
// This function will take each value from an object and obfuscate sensitive data
const myData = { apiKey: "super-secret-key" };
logger.info({ myData: obfuscateObject(myData) }, "Some log message");
// This is allowed, because the value is not a shorthand property
```
> **Warning**
> The rule checks only for shorthand properties, so this too will be allowed:
>
> ```ts
> const myData = { apiKey: "super-secret-key" };
> const { apiKey } = myData;
> logger.info({ apiKey }, "Some log message"); // oh no!
> ```
>
> You must check what values you pass to the logger function, the rule cannot dectect if a value is a secret or not
#### Options
This rule accepts an array of logger names used in your application.
For example, you are importing a logger from some file, the logger name is `myLogger`:
```ts
import { myLogger } from "./logger";
```
By default, the rule checks for logger object that's named `logger`.
The rule doesn't check if the logger was imported from specified file, just the name.
To check for your custom logger provide it as options to the rule
```json
{
"rules": {
"@saleor/saleor-app/logger-leak": ["error", ["logger", "myLogger"]]
}
}
```
> **Note**
> If you provide a config it will override the default configuration that checks for `logger`.
> If you use both `logger` and `myLogger` in your app, you need to specify both as shown in the example
## FAQ
### Misconfigured TypeScript parser
I get a following error:
```
You have used a rule which requires parserServices to be generated.
You must therefore provide a value for the "parserOptions.project" property for -eslint/parser.
```
#### 🏁 Fix
In your ESLint config add a configuration to point ESLint parser where your `tsconfig.json` is located
```json
{
"parserOptions": {
"project": "tsconfig.json"
}
}
```
If you're using a monorepo, and you're linting a package / app inside that monorepo remember that you also need to specify `tsconfigRootDir`
so that the `tsconfig.json` is relative to your package / app (not relative to root of monorepo).
```js
parserOptions: {
project: "tsconfig.json",
tsconfigRootDir: __dirname,
},
```
> **Note**
> You must use a JS file for ESLint config for it work (extension ending with `.js`, `.mjs`, `.cjs`)