@hasna/configs 0.2.10 → 0.2.11

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.
Files changed (2) hide show
  1. package/dist/mcp/index.js +34 -2
  2. package/package.json +1 -1
package/dist/mcp/index.js CHANGED
@@ -395,6 +395,12 @@ var init_apply = __esm(() => {
395
395
  });
396
396
 
397
397
  // src/lib/redact.ts
398
+ var exports_redact = {};
399
+ __export(exports_redact, {
400
+ scanSecrets: () => scanSecrets,
401
+ redactContent: () => redactContent,
402
+ hasSecrets: () => hasSecrets
403
+ });
398
404
  function redactShell(content) {
399
405
  const redacted = [];
400
406
  const lines = content.split(`
@@ -554,6 +560,13 @@ function redactContent(content, format) {
554
560
  return redactGeneric(content);
555
561
  }
556
562
  }
563
+ function scanSecrets(content, format) {
564
+ const r = redactContent(content, format);
565
+ return r.redacted;
566
+ }
567
+ function hasSecrets(content, format) {
568
+ return scanSecrets(content, format).length > 0;
569
+ }
557
570
  var SECRET_KEY_PATTERN, VALUE_PATTERNS, MIN_SECRET_VALUE_LEN = 8;
558
571
  var init_redact = __esm(() => {
559
572
  SECRET_KEY_PATTERN = /^(.*_?API_?KEY|.*_?TOKEN|.*_?SECRET|.*_?PASSWORD|.*_?PASSWD|.*_?CREDENTIAL|.*_?AUTH(?:_TOKEN|_KEY|ORIZATION)?|.*_?PRIVATE_?KEY|.*_?ACCESS_?KEY|.*_?CLIENT_?SECRET|.*_?SIGNING_?KEY|.*_?ENCRYPTION_?KEY|.*_AUTH_TOKEN)$/i;
@@ -1000,14 +1013,15 @@ var TOOL_DOCS = {
1000
1013
  list_profiles: "List all profiles. Returns array of profile objects.",
1001
1014
  apply_profile: "Apply all configs in a profile to disk. Params: id_or_slug, dry_run?. Returns array of apply results.",
1002
1015
  get_snapshot: "Get snapshot(s) for a config. Params: config_id_or_slug, version?. Returns latest snapshot or specific version.",
1003
- get_status: "Single-call orientation. Returns: total configs, counts by category, drifted count, unredacted secrets, templates, DB path.",
1016
+ get_status: "Single-call orientation. Returns: total configs, counts by category, templates, DB path.",
1017
+ scan_secrets: "Scan configs for unredacted secrets. Params: id_or_slug? (omit for all known), fix? (true to redact in-place). Returns findings.",
1004
1018
  sync_known: "Sync all known config files from disk into DB. Params: agent?, category?. Replaces sync_directory for standard use.",
1005
1019
  search_tools: "Search tool descriptions. Params: query. Returns matching tool names and descriptions.",
1006
1020
  describe_tools: "Get full descriptions for tools. Params: names? (array). Returns tool docs."
1007
1021
  };
1008
1022
  var PROFILES = {
1009
1023
  minimal: ["get_status", "get_config", "sync_known"],
1010
- standard: ["list_configs", "get_config", "create_config", "update_config", "apply_config", "sync_known", "get_status", "list_profiles", "apply_profile", "search_tools", "describe_tools"],
1024
+ standard: ["list_configs", "get_config", "create_config", "update_config", "apply_config", "sync_known", "get_status", "scan_secrets", "list_profiles", "apply_profile", "search_tools", "describe_tools"],
1011
1025
  full: []
1012
1026
  };
1013
1027
  var activeProfile = process.env["CONFIGS_PROFILE"] || "full";
@@ -1024,6 +1038,7 @@ var ALL_LEAN_TOOLS = [
1024
1038
  { name: "get_snapshot", inputSchema: { type: "object", properties: { config_id_or_slug: { type: "string" }, version: { type: "number" } }, required: ["config_id_or_slug"] } },
1025
1039
  { name: "get_status", inputSchema: { type: "object", properties: {} } },
1026
1040
  { name: "sync_known", inputSchema: { type: "object", properties: { agent: { type: "string" }, category: { type: "string" } } } },
1041
+ { name: "scan_secrets", inputSchema: { type: "object", properties: { id_or_slug: { type: "string" }, fix: { type: "boolean" } } } },
1027
1042
  { name: "search_tools", inputSchema: { type: "object", properties: { query: { type: "string" } }, required: ["query"] } },
1028
1043
  { name: "describe_tools", inputSchema: { type: "object", properties: { names: { type: "array", items: { type: "string" } } } } }
1029
1044
  ];
@@ -1131,6 +1146,23 @@ server.setRequestHandler(CallToolRequestSchema, async (req) => {
1131
1146
  });
1132
1147
  return ok(result);
1133
1148
  }
1149
+ case "scan_secrets": {
1150
+ const { scanSecrets: scanSecrets2, redactContent: redactContent2 } = await Promise.resolve().then(() => (init_redact(), exports_redact));
1151
+ const configs = args["id_or_slug"] ? [getConfig(args["id_or_slug"])] : listConfigs({ kind: "file" });
1152
+ const findings = [];
1153
+ for (const c of configs) {
1154
+ const fmt = c.format;
1155
+ const secrets = scanSecrets2(c.content, fmt);
1156
+ if (secrets.length > 0) {
1157
+ findings.push({ slug: c.slug, secrets: secrets.length, vars: secrets.map((s) => s.varName) });
1158
+ if (args["fix"]) {
1159
+ const { content, isTemplate } = redactContent2(c.content, fmt);
1160
+ updateConfig(c.id, { content, is_template: isTemplate });
1161
+ }
1162
+ }
1163
+ }
1164
+ return ok({ clean: findings.length === 0, findings, fixed: !!args["fix"] });
1165
+ }
1134
1166
  case "search_tools": {
1135
1167
  const query = (args["query"] || "").toLowerCase();
1136
1168
  const matches = Object.entries(TOOL_DOCS).filter(([k, v]) => k.includes(query) || v.toLowerCase().includes(query)).map(([name2, description]) => ({ name: name2, description }));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hasna/configs",
3
- "version": "0.2.10",
3
+ "version": "0.2.11",
4
4
  "description": "AI coding agent configuration manager — store, version, apply, and share all your AI coding configs. CLI + MCP + REST API + Dashboard.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",