SLD-904 - Introduce Azure Blob Storage logging destination - #14
Conversation
This commit updates the publish workflow to use the NPM environment instead of the legacy NPM-OIDC context and bumps the Socket CLI version in the security reachability workflow from 2.7.2 to 2.8.1.
The TypeScript path alias is preserved in emitted JavaScript, so Node needs the package imports map to resolve internal #/* module references at runtime. Without it, consumers receive ERR_PACKAGE_IMPORT_NOT_DEFINED.
This release adds @azure/storage-blob as an optional peer dependency and dev dependency, and bumps the package version to 0.0.4. It also updates the Vitest toolchain to 5.0.1 and refreshes the lockfile to match the new dependency graph.
Introduce an Azure Storage destination plugin that writes operational and audit logs to append blobs, plus shared option types and exported entry points. Add tests covering container setup, hourly blob rotation, disabled streams, validation, oversized records, append failures, and disposal behavior.
Update the lockfile to allow the Azure Blob Storage dependency to resolve with the caret range and refresh @types/node to 26.5.1. This keeps dependency resolution aligned with the current package constraints and avoids stale lockfile metadata.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
|
Warning Review the following alerts detected in dependencies. According to your organization's Security Policy, it is recommended to resolve "Warn" alerts. Learn more about Socket for GitHub.
|
🟢 Coverage Report
|
There was a problem hiding this comment.
Pull request overview
Adds an Azure Blob Storage logging destination with hourly operational and audit append blobs, tests, documentation, dependency updates, and CI tooling changes.
Changes:
- Added Azure destination implementation, configuration types, exports, and tests.
- Documented Azure setup and usage.
- Updated package metadata, lockfiles, and workflow tooling.
Reviewed changes
Copilot reviewed 8 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Summary | Review findings |
|---|---|---|
tests/plugins/AzureStorageDestination.test.ts |
Azure destination tests | None |
src/plugins/AzureStorageDestination.ts |
Azure append-blob destination | 4 moderate findings and 1 nit: public Azure type exposure, undefined size fallback, startup predicate checks, and misleading BlobAlreadyExists logging. |
src/interfaces/plugins/AzureStorageDestination.ts |
Configuration types and defaults | None |
src/index.ts |
Public exports | None |
README.md |
Azure usage documentation | 1 nit: LogEngine is used without initialization. |
package.json |
Package and dependency metadata | 1 moderate finding: optional Azure peer dependency conflicts with exported declaration requirements. |
package-lock.json |
Locked dependency updates | None |
.github/workflows/Security-Reachability.yml |
Security workflow tooling | None |
.github/workflows/Publish.yml |
Publishing workflow tooling | None |
Suppressed comments (5)
README.md:175
- This example imports
LogEnginebut never initializeslogEngine, so it does not compile (Cannot find name 'logEngine'). Addconst logEngine = LogEngine.getInstance();before this call so the documented integration is runnable.
await logEngine.addPlugin({
package.json:67
- Making
@azure/storage-bloban optional peer conflicts with exportingAzureStorageDestinationfrom the package root: its publiccreatesignature referencesContainerClientfrom that module, so the published declaration graph still requires TypeScript to resolve it. Consumers using only other destinations and following the README's claim that they do not need the SDK can therefore get a missing-module error while type-checking. Either make the peer required or expose SDK-independent structural types in the public declarations.
"peerDependencies": {
"@azure/storage-blob": "^12.33.0"
},
"peerDependenciesMeta": {
"@azure/storage-blob": {
"optional": true
src/plugins/AzureStorageDestination.ts:79
- The shared plugin contract says these predicates are evaluated when a destination processes a log (README.md:95), but this startup guard invokes
getShouldWriteOperationalLogsduringcreateand rejects whenever it is currently false. A runtime switch that starts disabled therefore cannot create this destination and later be enabled, unlike the other destinations; leave the predicate check inlogas the only gating behavior.
if (resolvedOptions.getShouldWriteOperationalLogs && !resolvedOptions.getShouldWriteOperationalLogs()) {
throw new Error('Operational logs are disabled by configuration but an operational log container was provided.');
}
src/plugins/AzureStorageDestination.ts:97
- This duplicates the startup-time predicate rejection for audit logs. It prevents a valid audit runtime switch from being initially false, even though the callback is intended to control writes at processing time; remove this check and let
auditLogperform the per-record check.
if (resolvedOptions.getShouldWriteAuditLogs && !resolvedOptions.getShouldWriteAuditLogs()) {
throw new Error('Audit logs are disabled by configuration but an audit log container was provided.');
}
src/plugins/AzureStorageDestination.ts:273
createIfNotExists()reports an existing blob as an unsuccessful response withBlobAlreadyExists, which is normal after a restart or when another instance already created the hourly blob. This branch labels that normal case asFailed to create new blobon every such write, producing misleading debug noise even though the subsequent append is valid; only report unexpected error codes.
if (result.errorCode) {
this.#writeDebugLog('Failed to create new blob:', result.errorCode);
}
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 9 changed files in this pull request and generated 5 comments.
Suppressed comments (1)
src/plugins/AzureStorageDestination.ts:97
- Evaluating the runtime write callback during creation prevents an initially disabled audit stream from ever being enabled later, even though
auditLog()reevaluates this callback for every record. Supplying its container while the callback is temporarily false should still be valid.
if (resolvedOptions.getShouldWriteAuditLogs && !resolvedOptions.getShouldWriteAuditLogs()) {
throw new Error('Audit logs are disabled by configuration but an audit log container was provided.');
}
Replace direct `@azure/storage-blob` type imports with local structural interfaces for append blob and container clients. This keeps the Azure storage destination compatible with the SDK at runtime while avoiding a hard dependency on its public TypeScript declarations.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: pr0uxx <michow289@hotmail.com>
Remove validation that threw errors when operational or audit log containers were provided but logging was disabled by configuration. This allows containers to be provided without enforcing that logging must be enabled.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: pr0uxx <michow289@hotmail.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Signed-off-by: pr0uxx <michow289@hotmail.com>
Introduces maxBlocksPerBlob configuration option to rotate append blobs when reaching Azure's 50,000 block limit. Refactors append logic from sequential queueing to efficient batch flushing, grouping pending records within byte limits and supporting blob rotation via numeric suffixes within the same hour. Improves throughput by batching records queued during in-flight flushes into single append operations.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 9 changed files in this pull request and generated 3 comments.
Suppressed comments (1)
src/plugins/AzureStorageDestination.ts:310
- This rounds in the host's local timezone but formats the blob name in UTC. In fractional-offset zones such as Asia/Kolkata,
03:04Zis rounded to02:30Z, producing a2025010202blob and rotating on the half-hour instead of the UTC hour. Round in UTC to keep the documented hourly names stable across hosts.
const activeHour = new Date().setMinutes(0, 0, 0);
Recover committed block counts when reopening existing append blobs, and use Azure's reported count after appends so concurrent writers stay in sync. This also skips over blobs that are already full instead of reusing them, with tests covering reopen, rotation, and count tracking.
Summary
Type Of Change
Activities Checklist
Code Quality
Testing And Validation
npm run validate:package.Coverage
Security And Safety
Documentation
Release Impact
Linked Work
Notes For Reviewers
#/*module references at runtime. Without it, consumers receiveERR_PACKAGE_IMPORT_NOT_DEFINED.