@saptools/cf-hana 0.1.5 → 0.1.6

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.6 - 2026-06-23
4
+
5
+ - Expand fake-backed E2E coverage for complex `UPDATE` and `DELETE` backups,
6
+ including mixed-case keywords, comments, quoted identifiers, nested queries,
7
+ placeholder filtering, and unscoped writes.
8
+ - Verify backup SELECT failures, write failures, filesystem failures, read-only
9
+ mode, malformed SQL, and parameter mismatches cannot bypass backup safety.
10
+ - Add opt-in fake-driver statement tracing and deterministic failure injection
11
+ without recording parameter values.
12
+
3
13
  ## 0.1.5 - 2026-06-23
4
14
 
5
15
  - Remove the CLI `--no-backup` opt-out so `cf-hana query` always attempts a
package/dist/cli.js CHANGED
@@ -514,7 +514,7 @@ async function listColumns(connection, schema, table) {
514
514
 
515
515
  // src/config.ts
516
516
  var CLI_NAME = "cf-hana";
517
- var CLI_VERSION = "0.1.5";
517
+ var CLI_VERSION = "0.1.6";
518
518
  var ENV_PREFIX = "CF_HANA";
519
519
  var DEFAULT_QUERY_TIMEOUT_MS = 3e4;
520
520
  var DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
@@ -633,7 +633,13 @@ function toConnectionTarget(binding, role) {
633
633
  }
634
634
 
635
635
  // src/driver/fake.ts
636
+ import { appendFile } from "fs/promises";
636
637
  function fakeExec(sql) {
638
+ const kind = classifyStatement(sql);
639
+ const forcedFailure = readEnv(envName("FAKE_FAIL_STATEMENT"))?.toLowerCase();
640
+ if (forcedFailure === kind) {
641
+ throw new Error(`fake driver forced ${kind.toUpperCase()} failure`);
642
+ }
637
643
  if (sql.toUpperCase().includes("DUMMY")) {
638
644
  return {
639
645
  rows: [{ "1": 1 }],
@@ -641,7 +647,6 @@ function fakeExec(sql) {
641
647
  affectedRows: 0
642
648
  };
643
649
  }
644
- const kind = classifyStatement(sql);
645
650
  if (kind === "select") {
646
651
  return {
647
652
  rows: [
@@ -660,10 +665,23 @@ function fakeExec(sql) {
660
665
  }
661
666
  return { rows: [], columns: [], affectedRows: 0 };
662
667
  }
668
+ async function traceFakeExec(sql, params) {
669
+ const tracePath = readEnv(envName("FAKE_TRACE_FILE"));
670
+ if (tracePath === void 0) {
671
+ return;
672
+ }
673
+ const entry = { sql, paramCount: params.length };
674
+ await appendFile(tracePath, `${JSON.stringify(entry)}
675
+ `, {
676
+ encoding: "utf8",
677
+ mode: 384
678
+ });
679
+ }
663
680
  var FakeConnection = class {
664
681
  closed = false;
665
- exec(sql, _params) {
666
- return Promise.resolve(fakeExec(sql));
682
+ async exec(sql, params) {
683
+ await traceFakeExec(sql, params);
684
+ return fakeExec(sql);
667
685
  }
668
686
  setAutoCommit(_enabled) {
669
687
  return Promise.resolve();
@@ -937,7 +955,7 @@ function createDriver(name) {
937
955
  }
938
956
 
939
957
  // src/history.ts
940
- import { appendFile, mkdir as mkdir2, readdir, rm } from "fs/promises";
958
+ import { appendFile as appendFile2, mkdir as mkdir2, readdir, rm } from "fs/promises";
941
959
  import { homedir as homedir2 } from "os";
942
960
  import { join as join2 } from "path";
943
961
  var SAPTOOLS_DIR_NAME2 = ".saptools";
@@ -999,7 +1017,7 @@ async function appendSqlHistory(input, options = {}) {
999
1017
  ...input
1000
1018
  };
1001
1019
  await mkdir2(historyDir, { recursive: true, mode: 448 });
1002
- await appendFile(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}
1020
+ await appendFile2(sqlHistoryFilePath(now, options.saptoolsRoot), `${JSON.stringify(entry)}
1003
1021
  `, {
1004
1022
  encoding: "utf8",
1005
1023
  mode: 384