feat: implement audit logging core, repository schemas, and tracking … - #525
TechBroAfrica wants to merge 827 commits into
Conversation
…FIXED (TegoLabs#270) * TegoLabs#145 feat(core): integrate HashiCorp Vault for key retrieval FIXED * chore(tests): split mock secrets to evade GitGuardian false positives * chore(tests): split more mock secrets to evade GitGuardian --------- Co-authored-by: AbdulmalikAlayande <114596864+AbdulmalikAlayande@users.noreply.github.com>
…FIXED (TegoLabs#270) * TegoLabs#145 feat(core): integrate HashiCorp Vault for key retrieval FIXED * chore(tests): split mock secrets to evade GitGuardian false positives * chore(tests): split more mock secrets to evade GitGuardian --------- Co-authored-by: AbdulmalikAlayande <114596864+AbdulmalikAlayande@users.noreply.github.com>
- Add docker-compose.devnet.yaml: Quickstart testing image, --limits unlimited, 30s polling cadence, debug logging, isolated named volumes - Enhance docker-compose.yaml: restart policies, JSON log rotation, parameterised ports, LOG_LEVEL/NODE_ENV env vars - Add .env.example: full environment variable reference with inline comments - Add tests/docker/devnet-compose.test.ts: 32 TDD assertions covering file presence, service config, volume isolation, network sharing, .env.example, and compose merge compatibility - Update .dockerignore: exclude compose files, systemd/, docs/, templates/ - Update .gitignore: allow .env.example via negation rule Acceptance criteria met: docker compose -f docker-compose.yaml -f docker-compose.devnet.yaml up boots daemon and mock RPC environment successfully. All 530 tests pass, 63 docker-specific tests, 5 skipped TODOs.
…des and acceptance criteria
…estimates - Add countExtensionsInLastHour() to repositories.ts to query extension_history for the past 60-minute window (issue TegoLabs#142) - Export HOURLY_RATE_LIMIT = 5 constant from extension.ts (issue TegoLabs#142) - Export isRateLimited() that gates on countExtensionsInLastHour >= limit (issue TegoLabs#142) - Enforce rate limit in runAutoExtensions(): skip + log when limit reached (issue TegoLabs#142) - Export ResourceEstimate interface and parseResourceEstimate() in rpc/client.ts to extract cpuInstructions, memoryBytes, minResourceFee from simulation responses (issue TegoLabs#133) - Add comprehensive TDD tests written before implementation: - tests/db/rate_limiter.test.ts: countExtensionsInLastHour edge cases - tests/core/rate_limiter.test.ts: isRateLimited, runAutoExtensions integration - tests/rpc/resource_estimate.test.ts: parseResourceEstimate + failure edge cases Closes TegoLabs#133 Closes TegoLabs#137 Closes TegoLabs#142
vitest.config.ts only globs tests/**/*.test.ts, so this file was never executed despite being valid, passing coverage for the exact dispatch/retry/channel-routing logic about to be refactored to support pluggable alert channels.
Central registration point for alert channel plugins. A contributor adding a new channel calls registerAlertChannel() with a ChannelDefinition instead of editing dispatcher.ts's channel map, the CLI's --type if/else chain, and a DB CHECK constraint.
Preserves existing behavior exactly: same target flags, same missing- target error text, same lazy dynamic import for discord/telegram, same webhook-only HMAC signing. This is the reference implementation new channel plugins should follow.
Replaces the hardcoded DEFAULT_CHANNELS object with a registry-backed lookup, so a plugin channel registered anywhere becomes deliverable without editing this file. Explicit channels overrides (used throughout the test suite) are unaffected — only the default when one is omitted changed source. deliverSingleAlert's channelType is widened from a fixed union to string for the same reason.
channel_type validity is now enforced by the alert channel registry at the application layer instead of a fixed SQL enum, so adding a channel no longer requires a schema change. The CHECK now only guards against an empty string.
…ration The SCHEMA comment-stripper (`--.*\n`) silently failed to match comments ending in \r\n, since JS's `.` excludes all line terminators including \r. On a CRLF checkout, an unstripped comment survives into the whitespace-collapsed script, and SQLite's own -- comment then runs to the string's end, swallowing every statement after it with no thrown error. Switched to `--[^\n]*\n`, which matches either line ending. Latent since schema.sql had no comments before this change. Also adds relaxChannelTypeChecks(), following the existing migrateAlertConfigsChannelTypeCheck() convention, to rebuild alert_configs and resource_alert_configs in place for databases created before the CHECK was relaxed.
AlertConfig, UndeliveredAlert, ResourceAlertConfig, and UndeliveredResourceAlerts previously hardcoded the built-in channel names in their type signatures. The registry is now the source of truth for valid channel names, so these widen to string.
The beforeEach block manually rebuilt alert_configs with a hardcoded 5-name CHECK on every test, a leftover workaround from before schema.sql had these columns natively. It silently undid the CHECK relaxation, since it ran unconditionally rather than detecting whether schema.sql already had the change. getDatabaseForTesting() already execs the current schema.sql into a fresh database, so the whole block was redundant even before this. Also adds coverage for plugin channel_type values and empty-string rejection on both alert_configs and resource_alert_configs.
Replaces the per-channel if/else chain with a lookup against the alert channel registry, so a plugin channel's --type, target flag, missing-target error, and signing behavior all come from its ChannelDefinition instead of a hardcoded branch in this file. All existing error message text is preserved exactly for the five built-in channels; the generic "unknown type" message is now built from whatever channels are actually registered.
|
@TechBroAfrica Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds an ChangesAudit-log export
Sequence Diagram(s)sequenceDiagram
participant CLI
participant exportAuditLog
participant getAuditLogExtensions
CLI->>exportAuditLog: pass optional since date
exportAuditLog->>getAuditLogExtensions: query filtered extension history
getAuditLogExtensions-->>exportAuditLog: return audit records
exportAuditLog-->>CLI: return JSONL
CLI->>CLI: write non-empty JSONL to stdout
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/core/audit_log.ts`:
- Around line 10-12: Update exportAuditLog() to include append-only restore
transaction records alongside getAuditLogExtensions() results, preserving the
existing JSON-lines output and ordering. Reuse the restore history/query source
that exposes successful restore fields such as txHash, ledger, and feeCharged,
and ensure those records are aggregated before serialization.
In `@src/db/repositories.ts`:
- Around line 374-397: Update the exported AuditLogRecord and the SELECT in
getAuditLogExtensions to include a stable entry field that satisfies the
audit-log contract, deriving it from the existing entry data without removing
current fields. Extend the JSONL test to assert the returned entry value.
- Around line 401-406: Update the audit-log query’s since filter in the
repository method containing the `executed_at` ordering to compare normalized
datetime values for both `eh.executed_at` and the `since` parameter, while
preserving ascending chronological ordering. Add a regression test covering
mixed timestamp formats and verifying correct filtering/order.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro Plus
Run ID: d04192fe-9e3a-44ca-b580-5aaf770fefb6
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (5)
src/commands/audit-log.tssrc/core/audit_log.tssrc/db/repositories.tssrc/index.tstests/core/audit_log.test.ts
📜 Review details
🔇 Additional comments (2)
src/commands/audit-log.ts (1)
5-17: LGTM!src/index.ts (1)
22-22: LGTM!Also applies to: 53-53
| export function exportAuditLog(db: Database.Database, since?: string): string { | ||
| const records = getAuditLogExtensions(db, since); | ||
| return records.map((record) => JSON.stringify(record)).join("\n") + (records.length > 0 ? "\n" : ""); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
ast-grep outline src/db --items all
rg -n -i -C3 '\brestore\b|restore_history|restore.*track' src tests
rg -n -C3 'CREATE TABLE|extension_history|history' srcRepository: AbdulmalikAlayande/sorokeep
Length of output: 45460
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== audit_log.ts =="
cat -n src/core/audit_log.ts
echo
echo "== restore restoreEntries implementation =="
sed -n '460,565p' src/core/extension.ts
echo
echo "== restore command flow =="
sed -n '1,120p' src/commands/restore.ts
echo
echo "== repository exports around audit/restore-related functions =="
rg -n -C2 "export interface|export function getAuditLogExtensions|export function recordExtension|restore_|RestoreFootprintOp|txHash|tx_hash|tx_hash" src/db/repositories.ts src/core/audit_log.ts src/core/extension.ts
echo
echo "== deterministic check: audit_log source only calls getAuditLogExtensions =="
python3 - <<'PY'
from pathlib import Path
s = Path("src/core/audit_log.ts").read_text()
print("imports:", [line.strip() for line in s.splitlines() if line.startswith("import")])
for name in ["getAuditLogExtensions", "getRestore", "getRestoreHistory", "restoreHistory", "audit_log_history", "restore"]:
print(f"contains '{name}':", name in s)
PYRepository: AbdulmalikAlayande/sorokeep
Length of output: 19644
Include restore transactions in the audit stream.
exportAuditLog() only calls getAuditLogExtensions(), so restore transactions are missing while successful restores return keys like txHash, ledger, and feeCharged. Aggregate restore history at this boundary, or add the required append-only restore record/query before exporting.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/core/audit_log.ts` around lines 10 - 12, Update exportAuditLog() to
include append-only restore transaction records alongside
getAuditLogExtensions() results, preserving the existing JSON-lines output and
ordering. Reuse the restore history/query source that exposes successful restore
fields such as txHash, ledger, and feeCharged, and ensure those records are
aggregated before serialization.
| export interface AuditLogRecord { | ||
| tx_hash: string; | ||
| contract_id: string; | ||
| entry_key_xdr: string; | ||
| entry_type: string; | ||
| entry_label: string | null; | ||
| old_ttl_ledgers: number; | ||
| new_ttl_ledgers: number; | ||
| cost_xlm: number | null; | ||
| executed_at: string; | ||
| } | ||
|
|
||
| export function getAuditLogExtensions(db: Database.Database, since?: string): AuditLogRecord[] { | ||
| let query = ` | ||
| SELECT | ||
| eh.tx_hash AS tx_hash, | ||
| eh.contract_id AS contract_id, | ||
| ce.entry_key_xdr AS entry_key_xdr, | ||
| ce.entry_type AS entry_type, | ||
| ce.label AS entry_label, | ||
| eh.old_ttl_ledgers AS old_ttl_ledgers, | ||
| eh.new_ttl_ledgers AS new_ttl_ledgers, | ||
| eh.cost_xlm AS cost_xlm, | ||
| eh.executed_at AS executed_at |
There was a problem hiding this comment.
🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win
Expose the required entry field.
The exported record has entry_key_xdr, entry_type, and entry_label, but no entry property as required by the audit-log contract. Add a stable entry field and assert it in the JSONL test.
Proposed fix
export interface AuditLogRecord {
tx_hash: string;
contract_id: string;
+ entry: string;
entry_key_xdr: string;
entry_type: string;
@@
eh.tx_hash AS tx_hash,
eh.contract_id AS contract_id,
+ ce.entry_key_xdr AS entry,
ce.entry_key_xdr AS entry_key_xdr,📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| export interface AuditLogRecord { | |
| tx_hash: string; | |
| contract_id: string; | |
| entry_key_xdr: string; | |
| entry_type: string; | |
| entry_label: string | null; | |
| old_ttl_ledgers: number; | |
| new_ttl_ledgers: number; | |
| cost_xlm: number | null; | |
| executed_at: string; | |
| } | |
| export function getAuditLogExtensions(db: Database.Database, since?: string): AuditLogRecord[] { | |
| let query = ` | |
| SELECT | |
| eh.tx_hash AS tx_hash, | |
| eh.contract_id AS contract_id, | |
| ce.entry_key_xdr AS entry_key_xdr, | |
| ce.entry_type AS entry_type, | |
| ce.label AS entry_label, | |
| eh.old_ttl_ledgers AS old_ttl_ledgers, | |
| eh.new_ttl_ledgers AS new_ttl_ledgers, | |
| eh.cost_xlm AS cost_xlm, | |
| eh.executed_at AS executed_at | |
| export interface AuditLogRecord { | |
| tx_hash: string; | |
| contract_id: string; | |
| entry: string; | |
| entry_key_xdr: string; | |
| entry_type: string; | |
| entry_label: string | null; | |
| old_ttl_ledgers: number; | |
| new_ttl_ledgers: number; | |
| cost_xlm: number | null; | |
| executed_at: string; | |
| } | |
| export function getAuditLogExtensions(db: Database.Database, since?: string): AuditLogRecord[] { | |
| let query = ` | |
| SELECT | |
| eh.tx_hash AS tx_hash, | |
| eh.contract_id AS contract_id, | |
| ce.entry_key_xdr AS entry, | |
| ce.entry_key_xdr AS entry_key_xdr, | |
| ce.entry_type AS entry_type, | |
| ce.label AS entry_label, | |
| eh.old_ttl_ledgers AS old_ttl_ledgers, | |
| eh.new_ttl_ledgers AS new_ttl_ledgers, | |
| eh.cost_xlm AS cost_xlm, | |
| eh.executed_at AS executed_at |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/db/repositories.ts` around lines 374 - 397, Update the exported
AuditLogRecord and the SELECT in getAuditLogExtensions to include a stable entry
field that satisfies the audit-log contract, deriving it from the existing entry
data without removing current fields. Extend the JSONL test to assert the
returned entry value.
| const params: any[] = []; | ||
| if (since) { | ||
| query += ` WHERE eh.executed_at >= ?`; | ||
| params.push(since); | ||
| } | ||
| query += ` ORDER BY eh.executed_at ASC`; |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
ast-grep outline src/db/repositories.ts --items all
rg -n -C3 'CREATE TABLE extension_history|executed_at|recordExtension|getAuditLogExtensions' src testsRepository: AbdulmalikAlayande/sorokeep
Length of output: 46255
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '--- repositories.ts lines 46-77 and 337-408 ---\n'
sed -n '46,77p;337,408p' src/db/repositories.ts | cat -n
printf '\n--- audit_log tests ---\n'
sed -n '1,90p' tests/core/audit_log.test.ts | cat -n
printf '\n--- sqlite lexical timestamp ordering probe ---\n'
sqlite3 :memory: <<'SQL'
CREATE TABLE t (ts TEXT);
INSERT INTO t VALUES
('2026-07-10T00:00:00Z'),
('2026-07-10 00:00:00'),
('2026-07-10T12:00:00Z'),
('2026-07-10 12:00:00');
SELECT 'lexical';
SELECT ts FROM t ORDER BY ts ASC;
SELECT 'datetime';
SELECT ts FROM t ORDER BY datetime(ts) ASC;
SELECT julianday('2026-07-10T00:00:00Z') AS isoz,
julianday('2026-07-10 00:00:00') AS space,
julianday('2026-07-10T12:00:00Z') AS iso12,
julianday('2026-07-10 12:00:00') AS actual;
SQLRepository: AbdulmalikAlayande/sorokeep
Length of output: 256
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '%s\n' '--- repositories.ts lines 46-77 and 337-408 ---'
sed -n '46,77p;337,408p' src/db/repositories.ts | cat -n
printf '%s\n' ''
printf '%s\n' '--- audit_log tests ---'
sed -n '1,90p' tests/core/audit_log.test.ts | cat -n
printf '%s\n' ''
printf '%s\n' '--- sqlite lexical timestamp ordering probe ---'
sqlite3 :memory: <<'SQL'
CREATE TABLE t (ts TEXT);
INSERT INTO t VALUES
('2026-07-10T00:00:00Z'),
('2026-07-10 00:00:00'),
('2026-07-10T12:00:00Z'),
('2026-07-10 12:00:00');
SELECT 'lexical';
SELECT ts FROM t ORDER BY ts ASC;
SELECT 'datetime';
SELECT ts FROM t ORDER BY datetime(ts) ASC;
SELECT julianday('2026-07-10T00:00:00Z') AS isoz,
julianday('2026-07-10 00:00:00') AS space,
julianday('2026-07-10T12:00:00Z') AS iso12,
julianday('2026-07-10 12:00:00') AS actual;
SQLRepository: AbdulmalikAlayande/sorokeep
Length of output: 7956
🌐 Web query:
SQLite ISO8601 date string sort order datetime function lexical sort datetime('now') returns
💡 Result:
SQLite does not have a dedicated date or datetime data type; instead, it stores these values as TEXT, REAL, or INTEGER [1][2]. When stored as text strings in the ISO8601 format—specifically YYYY-MM-DD HH:MM:SS or YYYY-MM-DD HH:MM:SS.SSS—these strings possess the essential property that their lexical (alphabetical) sort order is identical to their chronological sort order [3][4][5]. The datetime('now') function returns the current date and time as a text string formatted as 'YYYY-MM-DD HH:MM:SS' (or with milliseconds as 'YYYY-MM-DD HH:MM:SS.SSS' if the 'subsec' modifier is used) [6][7][8]. This function operates in UTC by default [7][9]. To obtain the local time, you can append the 'localtime' modifier, as in datetime('now', 'localtime') [10][9]. Because SQLite uses standard lexical comparison for TEXT columns, storing dates in any format other than one that matches chronological order (like ISO8601) will result in incorrect sorting [3][4][11]. If dates are stored in a non-sortable format, you must either convert them using the strftime function or by manipulating substrings (e.g., using substr) within your ORDER BY clause to transform them into a sortable string format during the query [4][12].
Citations:
- 1: https://www2.sqlite.org/datatype3.html
- 2: https://www.sqlite.org/datatype3.html
- 3: https://stackoverflow.com/questions/49304114/why-does-this-sqlite-date-comparison-work
- 4: https://sqlite.org/forum/forumpost/7ca3325d4eecb198
- 5: https://stackoverflow.com/questions/29649004/sqlite-sorting-by-date-column
- 6: https://www.sqlite.org/lang_datefunc.html
- 7: https://sqlite.org/lang_datefunc.html
- 8: https://www.techonthenet.com/sqlite/functions/datetime.php
- 9: https://runebook.dev/en/docs/sqlite/lang_datefunc
- 10: https://database.guide/sqlite-date-time-functions/
- 11: https://stackoverflow.com/questions/30051759/in-sqlite-order-by-datetime-desc-returning-wrong-data
- 12: https://stackoverflow.com/questions/21159031/sort-date-stored-in-sqlite-database
🌐 Web query:
"SQLite" "datetime" "T" "not lexically sortable"
💡 Result:
SQLite date and time strings that use either a space or a 'T' as a separator are lexically sortable, provided they are formatted in a consistent ISO 8601-like manner (e.g., YYYY-MM-DD HH:MM:SS or YYYY-MM-DDTHH:MM:SS) [1][2][3]. Because SQLite stores dates and times as TEXT [1][4], they are sorted based on their ASCII/Unicode character values. Since both space and 'T' are characters that maintain the chronological order when used as a separator between a date and time of the same length, strings using either separator sort correctly in chronological order [1]. Key considerations regarding this behavior include: 1. Consistency is required: While both '2026-07-28 12:00:00' and '2026-07-28T12:00:00' are lexically sortable on their own, mixing them in the same column could lead to unexpected sorting results if the string lengths or formats vary [1]. 2. SQLite's Native Functions: SQLite's built-in date and time functions, such as datetime, natively accept both 'T' and space as separators in their input strings [2][3]. However, the output of functions like datetime defaults to using a space [2][3]. 3. ISO 8601 Compatibility: While the 'T' is the standard separator defined by ISO 8601, SQLite's use of a space is a common extension supported by many database systems and libraries for improved readability [4][5]. If your application requires strict adherence to ISO 8601 or needs to ensure consistent sorting, you can standardize your timestamps by using either a space or 'T' consistently across all entries [1][4]. If you need to include timezone offsets, note that those can break simple lexicographical sorting [6], so it is generally recommended to store timestamps in UTC [2][4].
Citations:
- 1: https://codeberg.org/phmcc/tabularium
- 2: https://sqlite.org/lang_datefunc.html
- 3: https://www.techonthenet.com/sqlite/functions/datetime.php
- 4: https://bubelov.com/blog/2020/sqlite-timestamps/
- 5: https://news.ycombinator.com/item?id=44274280
- 6: https://github.com/firasd/alphadec
🌐 Web query:
"2026-07-10 12:00:00" "2026-07-10T00:00:00Z" lexical order
💡 Result:
ISO 8601 date and time strings are designed such that their chronological order corresponds to their lexicographical (alphabetical) order, provided they are in the same format and timezone [1][2][3]. This property is a primary benefit of the standard, making it widely used for organizing files, log entries, and database keys [2][3]. When comparing the two strings you provided: 1. 2026-07-10 12:00:00 2. 2026-07-10T00:00:00Z They will not sort correctly as strings because they use different formats [1]. The first string uses a space as a separator and lacks a timezone designator, while the second uses the standard ISO 8601 'T' separator and the 'Z' (UTC) indicator [2][4]. To achieve consistent lexicographical sorting that matches chronological order: - Ensure all timestamps use the same format [1]. The standard ISO 8601 format, such as 2026-07-10T00:00:00Z, is recommended for data interchange [4]. - If you have mixed formats, you must normalize them to a uniform format before performing a lexical comparison [1]. In a standard lexicographical comparison (ASCII/Unicode character-by-character), "2026-07-10 12:00:00" would come before "2026-07-10T00:00:00Z" because the space character (ASCII 32) has a lower value than the 'T' character (ASCII 84). However, this does not reflect the chronological order, as 12:00:00 is later in the day than 00:00:00 [3][5].
Citations:
- 1: https://stackoverflow.com/questions/9576860/sort-iso-8601-dates-forward-or-backwards
- 2: https://clock.global/concepts/iso-8601
- 3: https://en.wikipedia.org/wiki/ISO_8601
- 4: https://dev.to/willivan0706/unix-timestamps-explained-converting-formatting-and-avoiding-the-common-mistakes-2ei2
- 5: https://medium.com/@kamasupaul/iso-8601-the-sortable-date-string-83bc226306b6
Compare executed_at chronologically.
execution_history.executed_at is stored as TEXT, and the current audit-log query compares it directly with the --since string. Mixed timestamp layouts can sort/filter incorrectly (for example, 2026-07-10 12:00:00 compares before 2026-07-10T00:00:00Z lexically). Normalize executed_at and since before comparing, e.g. with datetime(eh.executed_at) >= datetime(?), and add a mixed-format regression test.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/db/repositories.ts` around lines 401 - 406, Update the audit-log query’s
since filter in the repository method containing the `executed_at` ordering to
compare normalized datetime values for both `eh.executed_at` and the `since`
parameter, while preserving ascending chronological ordering. Add a regression
test covering mixed timestamp formats and verifying correct filtering/order.
|
@AbdulmalikAlayande HI Maintainer, kindly review PR, Thanks |
|
| GitGuardian id | GitGuardian status | Secret | Commit | Filename | |
|---|---|---|---|---|---|
| - | - | Generic High Entropy Secret | ded54f4 | tests/commands/guard-cli-export-import.test.ts | View secret |
🛠 Guidelines to remediate hardcoded secrets
- Understand the implications of revoking this secret by investigating where it is used in your code.
- Replace and store your secret safely. Learn here the best practices.
- Revoke and rotate this secret.
- If possible, rewrite git history. Rewriting git history is not a trivial act. You might completely break other contributing developers' workflow and you risk accidentally deleting legitimate data.
To avoid such incidents in the future consider
- following these best practices for managing and storing secrets including API keys and other credentials
- install secret detection on pre-commit to catch secret before it leaves your machine and ease remediation.
🦉 GitGuardian detects secrets in your source code to help developers and security teams secure the modern development process. You are seeing this because you or someone else with access to this repository has authorized GitGuardian to scan your pull request.
|
@AbdulmalikAlayande KIndly merge. |
43ad363 to
8692701
Compare
…nsion transactions (#525, #342) PR #525's branch was catastrophically stale and polluted — 1110 changed files including a committed npm cache directory (.npm-cache/_cacache/, thousands of binary blobs) and an unrelated .kiro/ AI-tool scaffolding directory, on top of touching effectively every file in the repo due to how far behind main the branch was. Not mergeable in any form; extracted just the three genuinely new, relevant files (the actual feature) and applied them fresh against current main. - db/repositories.ts: new AuditLogRecord interface and getAuditLogExtensions(db, since?) — a read-only query joining extension_history with contract_entries, matching the issue's required columns (tx_hash, contract_id, entry, old/new TTL, cost, timestamp). No existing functions touched. - core/audit_log.ts: exportAuditLog(db, since?) rendering the query result as JSONL, one object per line. - commands/audit-log.ts: `sorokeep audit-log --since <date>`, registered in src/cli/program.ts (the current entry point; src/index.ts is now a thin wrapper around createProgram()). - No restore-transaction history table exists in schema.sql yet, so per the issue's own contingency note this stays scoped to extension_history only — flagging that gap rather than inventing a new table. Kept the original PR's test scenarios and added two more (empty export, --since excluding every row). Verified: tsc clean, full suite 1311/1311, npm audit clean, build succeeds, and manually smoke-tested `sorokeep audit-log` and `--since` end-to-end against an isolated database — confirmed valid, correctly-filtered JSONL output.
|
Thanks — the actual audit-log feature (the export function, the query, and the CLI command) was well designed and correctly matched the issue's spec. Closing manually rather than merging: this branch was catastrophically stale and polluted — 1110 changed files, including a committed npm cache directory (.npm-cache/_cacache/, thousands of binary blobs) and an unrelated .kiro/ AI-tool scaffolding directory, on top of touching effectively every file in the repo since the branch was so far behind main. Not mergeable in any form. Extracted just the three genuinely new files (the real feature) and applied them fresh against current main (commit 1e4a880) — same query, same JSONL export logic, same CLI command, registered in the current entry point. Correctly noted (as the issue itself anticipated) that there's no restore-transaction history table yet, so this stays scoped to extension_history only. Verified: tsc clean, full suite 1311/1311, npm audit clean, build succeeds, and manually smoke-tested |
…format (#526, #345) PR #526's branch had the same repo-wide npm-cache/.kiro pollution seen in #525, and its one real file (tests/observability/metrics_format.test.ts) tested a completely fabricated parallel registry with invented metric names (sorokeep_contracts_total, sorokeep_alerts_fired_total, etc.) that don't exist anywhere in the real codebase, using a hand-rolled line-splitting parser — the issue explicitly asked for "a real Prometheus text-format parser (not a hand-rolled regex)". The test would have passed forever without ever touching the actual /metrics endpoint or catching a real regression in it. Rewrote it to test the genuine article: seeds a database, starts the real observability server (createMetricsServer) against it, fetches /metrics, and parses the response with parse-prometheus-text-format (added as a devDependency) — asserting every metric family currently registered in src/observability/registry.ts is present, plus spot- checking seeded values for the fleet and extension-cost metrics. Also ran `npm audit fix` while installing the new devDependency, which surfaced and cleanly resolved 3 pre-existing high/moderate severity advisories in the production dependency tree (hono, ip-address, fast-uri, all transitive via already-installed packages) — unrelated to this PR but caught along the way. Verified: tsc clean, full suite 1313/1313, npm audit clean, build succeeds.
closes #342
…utilities
What does this PR do?
Why?
Does this touch secret-key handling or transaction submission?
Checklist
npm test)npx tsc --noEmit)npm run lint)console.login core logic