@cleartrip/frontguard 0.1.8 → 0.1.9
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/dist/cli.js +22 -9
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/bitbucket-pipelines.yml +45 -54
- package/templates/freekit-ci-setup.md +20 -0
package/dist/index.d.ts
CHANGED
|
@@ -59,6 +59,7 @@ interface FrontGuardConfig {
|
|
|
59
59
|
};
|
|
60
60
|
};
|
|
61
61
|
prSize: {
|
|
62
|
+
enabled: boolean;
|
|
62
63
|
warnLines: number;
|
|
63
64
|
softBlockLines: number;
|
|
64
65
|
};
|
|
@@ -96,6 +97,11 @@ interface FrontGuardConfig {
|
|
|
96
97
|
buildCommand: string;
|
|
97
98
|
measureGlobs: string[];
|
|
98
99
|
baselinePath: string;
|
|
100
|
+
/**
|
|
101
|
+
* Git ref used to read `baselinePath` from the base branch when the file is not on disk
|
|
102
|
+
* (e.g. `main` or `master`). Separate from `tsAnyDelta.baseRef` so bundle can track a release branch.
|
|
103
|
+
*/
|
|
104
|
+
baselineRef: string;
|
|
99
105
|
maxDeltaBytes: number | null;
|
|
100
106
|
maxTotalBytes: number | null;
|
|
101
107
|
};
|
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ var defaultConfig = {
|
|
|
82
82
|
tsAnyDeltaToBlock: true
|
|
83
83
|
}
|
|
84
84
|
},
|
|
85
|
-
prSize: { warnLines: 400, softBlockLines: 800 },
|
|
85
|
+
prSize: { enabled: true, warnLines: 400, softBlockLines: 800 },
|
|
86
86
|
tsAnyDelta: {
|
|
87
87
|
enabled: true,
|
|
88
88
|
gate: "warn",
|
|
@@ -90,24 +90,25 @@ var defaultConfig = {
|
|
|
90
90
|
maxAdded: 0
|
|
91
91
|
},
|
|
92
92
|
cycles: {
|
|
93
|
-
enabled:
|
|
93
|
+
enabled: true,
|
|
94
94
|
gate: "warn",
|
|
95
95
|
entries: ["src"],
|
|
96
96
|
extraArgs: []
|
|
97
97
|
},
|
|
98
98
|
deadCode: {
|
|
99
|
-
enabled:
|
|
99
|
+
enabled: true,
|
|
100
100
|
gate: "info",
|
|
101
101
|
extraArgs: [],
|
|
102
102
|
maxReportLines: 80
|
|
103
103
|
},
|
|
104
104
|
bundle: {
|
|
105
|
-
enabled:
|
|
105
|
+
enabled: true,
|
|
106
106
|
gate: "warn",
|
|
107
107
|
runBuild: true,
|
|
108
108
|
buildCommand: "npm run build",
|
|
109
109
|
measureGlobs: ["dist/**/*", "build/static/**/*", ".next/static/**/*"],
|
|
110
110
|
baselinePath: ".frontguard/bundle-baseline.json",
|
|
111
|
+
baselineRef: "main",
|
|
111
112
|
maxDeltaBytes: null,
|
|
112
113
|
maxTotalBytes: null
|
|
113
114
|
},
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../node_modules/defu/dist/defu.mjs","../src/config/defaults.ts","../src/index.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"sources":["../node_modules/defu/dist/defu.mjs","../src/config/defaults.ts","../src/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["function isPlainObject(value) {\n if (value === null || typeof value !== \"object\") {\n return false;\n }\n const prototype = Object.getPrototypeOf(value);\n if (prototype !== null && prototype !== Object.prototype && Object.getPrototypeOf(prototype) !== null) {\n return false;\n }\n if (Symbol.iterator in value) {\n return false;\n }\n if (Symbol.toStringTag in value) {\n return Object.prototype.toString.call(value) === \"[object Module]\";\n }\n return true;\n}\n\nfunction _defu(baseObject, defaults, namespace = \".\", merger) {\n if (!isPlainObject(defaults)) {\n return _defu(baseObject, {}, namespace, merger);\n }\n const object = { ...defaults };\n for (const key of Object.keys(baseObject)) {\n if (key === \"__proto__\" || key === \"constructor\") {\n continue;\n }\n const value = baseObject[key];\n if (value === null || value === void 0) {\n continue;\n }\n if (merger && merger(object, key, value, namespace)) {\n continue;\n }\n if (Array.isArray(value) && Array.isArray(object[key])) {\n object[key] = [...value, ...object[key]];\n } else if (isPlainObject(value) && isPlainObject(object[key])) {\n object[key] = _defu(\n value,\n object[key],\n (namespace ? `${namespace}.` : \"\") + key.toString(),\n merger\n );\n } else {\n object[key] = value;\n }\n }\n return object;\n}\nfunction createDefu(merger) {\n return (...arguments_) => (\n // eslint-disable-next-line unicorn/no-array-reduce\n arguments_.reduce((p, c) => _defu(p, c, \"\", merger), {})\n );\n}\nconst defu = createDefu();\nconst defuFn = createDefu((object, key, currentValue) => {\n if (object[key] !== void 0 && typeof currentValue === \"function\") {\n object[key] = currentValue(object[key]);\n return true;\n }\n});\nconst defuArrayFn = createDefu((object, key, currentValue) => {\n if (Array.isArray(object[key]) && typeof currentValue === \"function\") {\n object[key] = currentValue(object[key]);\n return true;\n }\n});\n\nexport { createDefu, defu as default, defu, defuArrayFn, defuFn };\n","import type { FrontGuardConfig } from './schema.js'\n\nexport const defaultConfig: FrontGuardConfig = {\n mode: 'warn',\n rules: {},\n checks: {\n eslint: { enabled: true, glob: '**/*.{js,cjs,mjs,jsx,ts,tsx}' },\n prettier: {\n enabled: true,\n glob: '**/*.{js,cjs,mjs,jsx,ts,tsx,json,md,css,scss,yml,yaml}',\n },\n typescript: { enabled: true },\n secrets: { enabled: true },\n prHygiene: {\n enabled: true,\n minBodyLength: 80,\n requireSections: false,\n sectionHints: ['what', 'why', 'test', 'how to test', 'screenshot'],\n requireAiDisclosureSection: true,\n gateWhenAiDisclosureAmbiguous: 'warn',\n },\n aiAssistedReview: {\n enabled: true,\n gate: 'warn',\n escalate: {\n secretFindingsToBlock: true,\n tsAnyDeltaToBlock: true,\n },\n },\n prSize: { enabled: true, warnLines: 400, softBlockLines: 800 },\n\n tsAnyDelta: {\n enabled: true,\n gate: 'warn',\n baseRef: 'main',\n maxAdded: 0,\n },\n cycles: {\n enabled: true,\n gate: 'warn',\n entries: ['src'],\n extraArgs: [],\n },\n deadCode: {\n enabled: true,\n gate: 'info',\n extraArgs: [],\n maxReportLines: 80,\n },\n bundle: {\n enabled: true,\n gate: 'warn',\n runBuild: true,\n buildCommand: 'npm run build',\n measureGlobs: ['dist/**/*', 'build/static/**/*', '.next/static/**/*'],\n baselinePath: '.frontguard/bundle-baseline.json',\n baselineRef: 'main',\n maxDeltaBytes: null,\n maxTotalBytes: null,\n },\n cwv: {\n enabled: true,\n gate: 'warn',\n scanGlobs: ['app/**/*.{tsx,jsx}', 'pages/**/*.{tsx,jsx}', 'src/**/*.{tsx,jsx}'],\n maxFileBytes: 400_000,\n },\n llm: {\n enabled: false,\n provider: 'openai',\n model: 'gpt-4o-mini',\n apiKeyEnv: 'OPENAI_API_KEY',\n maxDiffChars: 48_000,\n timeoutMs: 60_000,\n ollamaUrl: 'http://127.0.0.1:11434',\n perFindingFixes: false,\n maxFixSuggestions: 12,\n maxFileContextChars: 24_000,\n },\n },\n}\n","import defu from 'defu'\nimport type { FrontGuardConfig } from './config/schema.js'\nimport { defaultConfig } from './config/defaults.js'\n\nexport type {\n FrontGuardConfig,\n GuardMode,\n CheckGate,\n RulesMap,\n CustomRuleDefinition,\n RuleFileContext,\n} from './config/schema.js'\nexport { defaultConfig } from './config/defaults.js'\n\n/**\n * Define repo-level config; shallow-merged over built-in defaults.\n * Org packages can be referenced via `extends` in config file.\n */\nexport function defineConfig(partial: Partial<FrontGuardConfig>): FrontGuardConfig {\n return defu(partial, defaultConfig) as FrontGuardConfig\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,49 +1,17 @@
|
|
|
1
|
-
# FrontGuard + PR comment (Bitbucket Cloud)
|
|
1
|
+
# FrontGuard + PR comment (Bitbucket Cloud) — FreeKit.dev report URL
|
|
2
2
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# Name: BITBUCKET_ACCESS_TOKEN
|
|
6
|
-
# Value: API token with permission to comment on pull requests (rotate if ever leaked).
|
|
7
|
-
# 2. Add @cleartrip/frontguard as a devDependency and commit this as bitbucket-pipelines.yml
|
|
8
|
-
# at the repository root, or merge the pull-requests section into your existing pipelines file.
|
|
9
|
-
#
|
|
10
|
-
# API hostname MUST be api.bitbucket.org (Bitbucket Cloud). Do not substitute DOCKER_*,
|
|
11
|
-
# NPM registry, or other host variables here — wrong host → 401/403 and requests never hit Bitbucket.
|
|
12
|
-
# Self-hosted Bitbucket Server uses a different REST path; this template is Cloud-only.
|
|
13
|
-
#
|
|
14
|
-
# BITBUCKET_REPO_FULL_NAME = workspace/slug (e.g. myworkspace/myrepo). BITBUCKET_PR_ID is numeric.
|
|
15
|
-
#
|
|
16
|
-
# Duplicate comments: each run adds a new comment. To upsert one comment, add a script that
|
|
17
|
-
# GETs /pullrequests/{id}/comments and DELETEs or updates the previous FrontGuard comment.
|
|
18
|
-
#
|
|
19
|
-
# ⚠️ CRITICAL — What to POST as the PR comment:
|
|
20
|
-
# Use ONLY `frontguard-pr-comment.md` (short, plain summary + pipeline URL for the HTML artifact).
|
|
21
|
-
# NEVER POST `frontguard-report.md` or the raw `yarn frontguard run` stdout — that is the full
|
|
22
|
-
# markdown report and will look like a wall of `##` / `|` if something goes wrong, and is
|
|
23
|
-
# unreadable in a PR thread. The interactive HTML is `frontguard-report.html` (Artifacts).
|
|
24
|
-
#
|
|
25
|
-
# API: body MUST be `{"content":{"raw":"<text>"}}` only. Do not add `content.markup` — Bitbucket
|
|
26
|
-
# returns 400 "extra keys not allowed". Markdown in `raw` is still rendered when possible.
|
|
27
|
-
#
|
|
28
|
-
# PR comments: Bitbucket Markdown is limited (no raw HTML). To share the rich HTML report:
|
|
29
|
-
#
|
|
30
|
-
# A) Default (no extra setup): the comment links to **this pipeline’s results page**. That URL works for
|
|
31
|
-
# anyone with repo access who is **logged into Bitbucket**. They click **Artifacts** →
|
|
32
|
-
# **frontguard-report.html** → download → open the file locally (full UI: accordions, colors, findings).
|
|
33
|
-
# Bitbucket does **not** offer a stable public “open HTML inline in one click” URL for step artifacts.
|
|
3
|
+
# HTML report is uploaded to https://freekit.dev via their public API (no API key for POST /sites).
|
|
4
|
+
# Docs: https://freekit.dev/docs
|
|
34
5
|
#
|
|
35
|
-
#
|
|
36
|
-
#
|
|
37
|
-
#
|
|
6
|
+
# Per-repo setup:
|
|
7
|
+
# 1. Repository variable (secured): BITBUCKET_ACCESS_TOKEN — permission to comment on pull requests.
|
|
8
|
+
# 2. Add @cleartrip/frontguard as a devDependency and use this file (or merge the step).
|
|
38
9
|
#
|
|
39
|
-
#
|
|
40
|
-
# downloads (`repository:write`). The comment then points at **Repository → Downloads** + filename.
|
|
10
|
+
# API hostname for comments MUST be api.bitbucket.org (Bitbucket Cloud).
|
|
41
11
|
#
|
|
42
|
-
#
|
|
12
|
+
# The PR comment body is the hosted https://freekit.dev/s/... URL (one line).
|
|
43
13
|
#
|
|
44
|
-
#
|
|
45
|
-
# "ollama"` + `perFindingFixes: true` on self-hosted runners or locally; otherwise use cloud
|
|
46
|
-
# keys or `--append` with pasted review notes.
|
|
14
|
+
# Caveats (see templates/freekit-ci-setup.md): public URL, third-party service, size/rate limits.
|
|
47
15
|
|
|
48
16
|
image: node:20
|
|
49
17
|
|
|
@@ -51,7 +19,7 @@ pipelines:
|
|
|
51
19
|
pull-requests:
|
|
52
20
|
'**':
|
|
53
21
|
- step:
|
|
54
|
-
name: FrontGuard –
|
|
22
|
+
name: FrontGuard – FreeKit report + PR comment
|
|
55
23
|
caches:
|
|
56
24
|
- node
|
|
57
25
|
artifacts:
|
|
@@ -63,23 +31,46 @@ pipelines:
|
|
|
63
31
|
- |
|
|
64
32
|
yarn frontguard run --markdown \
|
|
65
33
|
--htmlOut frontguard-report.html \
|
|
66
|
-
--prCommentOut frontguard-pr-comment.md \
|
|
67
34
|
> frontguard-report.md
|
|
68
|
-
- grep -q "FrontGuard report (short summary)" frontguard-pr-comment.md || { echo "frontguard-pr-comment.md missing or wrong FrontGuard version; upgrade @cleartrip/frontguard and keep --prCommentOut"; exit 1; }
|
|
69
|
-
# Optional: upload HTML to repo Downloads, then append a second link to the comment file.
|
|
70
|
-
# Requires a token with permission to POST /downloads (often `repository:write` in addition to PR comment).
|
|
71
|
-
# - FG_REPORT_NAME="frontguard-pr-${BITBUCKET_PR_ID}-b${BITBUCKET_BUILD_NUMBER}.html"
|
|
72
|
-
# - cp frontguard-report.html "$FG_REPORT_NAME"
|
|
73
|
-
# - curl -f -sS -X POST "https://api.bitbucket.org/2.0/repositories/${BITBUCKET_REPO_FULL_NAME}/downloads" \
|
|
74
|
-
# -H "Authorization: Bearer ${BITBUCKET_ACCESS_TOKEN}" -F "files=@${FG_REPORT_NAME}"
|
|
75
|
-
# - printf '\n\n**HTML report:** [Repository downloads](https://bitbucket.org/%s/downloads/) — look for `%s`.\n' "${BITBUCKET_REPO_FULL_NAME}" "$FG_REPORT_NAME" >> frontguard-pr-comment.md
|
|
76
35
|
- |
|
|
77
36
|
python3 << 'PY'
|
|
78
37
|
import json
|
|
79
|
-
|
|
80
|
-
|
|
38
|
+
import os
|
|
39
|
+
from urllib.error import HTTPError
|
|
40
|
+
from urllib.request import Request, urlopen
|
|
41
|
+
|
|
42
|
+
base = os.environ.get("FREEKIT_BASE_URL", "https://freekit.dev").rstrip("/")
|
|
43
|
+
|
|
44
|
+
with open("frontguard-report.html", encoding="utf-8") as f:
|
|
45
|
+
html = f.read()
|
|
46
|
+
|
|
47
|
+
req = Request(
|
|
48
|
+
f"{base}/api/v1/sites",
|
|
49
|
+
data=json.dumps({"html": html}).encode("utf-8"),
|
|
50
|
+
headers={"Content-Type": "application/json"},
|
|
51
|
+
method="POST",
|
|
52
|
+
)
|
|
53
|
+
try:
|
|
54
|
+
with urlopen(req, timeout=180) as resp:
|
|
55
|
+
parsed = json.load(resp)
|
|
56
|
+
except HTTPError as e:
|
|
57
|
+
raise SystemExit(
|
|
58
|
+
f"FreeKit HTTP {e.code}: {(e.read() or b'').decode()[:4000]}"
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
if parsed.get("status") != "success":
|
|
62
|
+
raise SystemExit(f"FreeKit error: {json.dumps(parsed)[:4000]}")
|
|
63
|
+
|
|
64
|
+
data = parsed.get("data") or {}
|
|
65
|
+
url = (data.get("url") or "").strip()
|
|
66
|
+
if not url:
|
|
67
|
+
raise SystemExit(f"FreeKit: missing data.url in {json.dumps(parsed)[:2000]}")
|
|
68
|
+
|
|
69
|
+
with open("frontguard-pr-comment.md", "w", encoding="utf-8") as out:
|
|
70
|
+
out.write(url + "\n")
|
|
71
|
+
|
|
81
72
|
with open("frontguard-payload.json", "w", encoding="utf-8") as out:
|
|
82
|
-
json.dump({"content": {"raw":
|
|
73
|
+
json.dump({"content": {"raw": url}}, out, ensure_ascii=False)
|
|
83
74
|
PY
|
|
84
75
|
- |
|
|
85
76
|
test -n "${BITBUCKET_ACCESS_TOKEN:-}" || { echo "Missing secured var BITBUCKET_ACCESS_TOKEN"; exit 1; }
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# FreeKit.dev + FrontGuard (Bitbucket Pipelines)
|
|
2
|
+
|
|
3
|
+
The Bitbucket template uploads `frontguard-report.html` with **no signup or API key**, using FreeKit’s public API:
|
|
4
|
+
|
|
5
|
+
- **Docs:** [FreeKit API](https://freekit.dev/docs)
|
|
6
|
+
- **Endpoint:** `POST https://freekit.dev/api/v1/sites` with JSON `{"html": "<full report html>"}`
|
|
7
|
+
- **Response:** `data.url` like `https://freekit.dev/s/<siteId>` — this URL is posted as the PR comment.
|
|
8
|
+
|
|
9
|
+
Optional env (advanced): **`FREEKIT_BASE_URL`** — override the API host (e.g. self‑hosted instance per FreeKit docs).
|
|
10
|
+
|
|
11
|
+
## Things to know
|
|
12
|
+
|
|
13
|
+
- **Public:** Anyone with the link can open the report. Do not use for highly sensitive content unless you add FreeKit **password** protection via their API (requires passing `password` in the JSON — not in this template).
|
|
14
|
+
- **Third party:** Uptime, limits, and terms are those of [FreeKit](https://freekit.dev); not controlled by Cleartrip/FrontGuard.
|
|
15
|
+
- **Limits:** Per FreeKit docs — e.g. HTML payload size caps, **rate limits** (creates per minute per IP), possible `429`. Large reports or busy runners may need retries or another host.
|
|
16
|
+
- **No delete token in CI:** Each run creates a **new** site URL. Old FreeKit URLs may still work until you delete them with the `deleteToken` returned in the API response (this template does not store it).
|
|
17
|
+
|
|
18
|
+
## Compared to Surge
|
|
19
|
+
|
|
20
|
+
Surge credentials (`SURGE_LOGIN` / `SURGE_TOKEN`) are **not** required for FreeKit’s open POST flow. If you remove Surge, you can delete any old Surge-related secured variables from the repository.
|