[New Integration] TYCHON Quantum Command integration package - #20142
Audience2801 wants to merge 82 commits into
Conversation
|
💚 CLA has been signed |
ReviewersBuildkite won't run for external contributors automatically; you need to add a comment:
NOTE: https://github.com/elastic/integrations/blob/main/.buildkite/pull-requests.json contains all those details. |
… in README Template with {{ fields tychon_pqc }} and {{ event tychon_pqc }} - replaced dashboard and supporting objects with those output from 'elastic-package export dashboards' command.
Deleted 14 standalone visualization saved objects that are no longer referenced by the package dashboards after converting visualization panels to by-value embeds. Confirmed all remaining data views are still referenced: - 05179988-8b3d-4f26-9832-d83a1e769b2d: used by application-report, application-detail, and DoD OMB report search - 1dc9d581-4b38-4108-84e1-59a9fbcfbca5: used by Certificate Inventory Detail search for runtime fields and duration formatting - 852a2806-9a09-4c17-bcea-b54e7b69f3bc: used by application-detail dashboard
There was a problem hiding this comment.
This appears to have come back. Please deleted it.
… query handling Expanded summary: - Correct inverted Vega filter-toggle ternaries so selected rows remove filters and unselected rows add them. - Add consistent empty-state indicators to Vega query panels. - Add missing time bindings to certificate dashboard Vega queries, using Kibana-compatible dashboard context where explicit queries are required. - Fix Certificate Source Type panel by replacing invalid %context% + body.query usage with dashboard context placeholders and %timefilter%. - Add a topology truncation warning for the 500-relationship composite bucket limit. - Add regression tests covering Vega toggle behavior, time binding presence, empty-state indicators, and topology truncation disclosure. - Updated .github/CODEOWNERS and manifest.yml with correct owners. - Removed LICENSE.txt and sample_event.json.
…panel in [tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology.json]. The Vega APPLY button still calls kibanaAddFilter(activeFilter), but there is no longer a panel-level filter-trigger drilldown intercepting that action and opening the pop-up.
| on_failure: | ||
| - append: | ||
| field: error.pipeline | ||
| value: "Failed to parse certificate.not_after: {{_ingest.on_failure_message}}" |
There was a problem hiding this comment.
Failures in these date and convert processors will mean that the type is not mappable, and so the resulting document will be rejected. If there is a failure, the field should be removed.
There was a problem hiding this comment.
This has not been resolved, just moved.
There was a problem hiding this comment.
We addressed this in two parts.
First, the recoverable date/convert failures now remove the invalid mapped values instead of leaving them behind. The date failure handlers remove the original field plus derived copies such as x509.* and tychon.certificate_leaf_details/tychon.cipher_negotiation fields. The convert failure handlers remove invalid numeric values from tychon.application.port and tychon.application.port_quantum_grade.score.
Second, we normalized the recoverable failure messages to the conventional processor/type/tag/pipeline/message wording so the failure identifies the processor type, processor tag, pipeline, and underlying error.
One implementation note: these recoverable sanitization warnings are stored in error.pipeline rather than error.message because elastic-package treats populated error.message as an unexpected pipeline error for documents that were successfully sanitized and indexed. The fatal top-level on_failure path still uses error.message and we’ll handle that separately in the next cleanup step.
There was a problem hiding this comment.
The pipeline here puts values into non-ECS fields that are not tychon_quantum_command.* namespaced. Please ensure that public fields follow ECS.
There was a problem hiding this comment.
We understand the concern that package-specific fields should normally align with the package/data stream namespace. In our case, tychon.* is the established TYCHON vendor namespace used across our data model, and we have not historically represented TYCHON data under tychon_quantum_command.tychon_pqc.*.
We would prefer to keep tychon.* for TYCHON-specific fields so this integration remains consistent with existing TYCHON field conventions. Renaming the package to tychon is not possible as a package with a that name, serving a different function, already exists.
There was a problem hiding this comment.
@jamiehynds Do Tychon have a special arrangement for working outside ECS conventions?
There was a problem hiding this comment.
@efd6 its been awhile but I think @chrisberkhout ran into this with the Tychon Agentless integration and can probably explain where we landed in the end.
There was a problem hiding this comment.
The tychon.* namespace is used in the TYCHON Agentless (tychon) integration.
I don't foresee a problem with several Tychon integrations putting fields under the one tychon.* namespace.
But we should keep non-ECS field inside the the vendor prefixed namespace. Looking through some of the other comments and the expected pipeline test outputs, there are a lot of non-ECS top level fields. e.g. kerberos.
With all the transforms, it would be good to keep source and destination field definitions in sync. It's possible to use elastic-package links to replace a duplicate file with a link that points to the original. If different transform destinations have different subsets of field definitions, each could be in a separate fields/*.yml file, and e.g. elasticsearch/transform/applications/fields/application.yml could be a link to data_stream/tychon_pqc/fields/application.yml.
There was a problem hiding this comment.
There are quite a few non-conformant fields.
Wrong top-level namespaces (not ECS, not tychon.*)
| Field | Reason |
|---|---|
macsec.* (group) |
macsec is not an ECS namespace; should be tychon.macsec.* |
archive.* (group) |
archive is not an ECS namespace; should be tychon.archive.* |
Invalid sub-fields under ECS namespaces
| Field | Reason |
|---|---|
hash.sha256_certificate |
ECS hash only defines cdhash, md5, sha1, sha256, sha384, sha512, ssdeep |
x509.is_ca |
Not an ECS x509 field |
x509.is_valid |
Not an ECS x509 field |
x509.validity.not_after |
ECS has x509.not_after directly, not under x509.validity.* |
x509.validity.not_before |
Same |
file.permissions |
ECS has file.mode, not file.permissions |
file.group.name |
ECS defines file.group as a plain keyword — making it an object with .name conflicts |
file.owner.name |
Same — ECS has file.owner as a plain keyword |
host.cpu.cores |
ECS only defines host.cpu.usage |
host.memory.total |
Not in ECS |
observer.domain |
Not in ECS (ECS has observer.hostname, observer.name, not observer.domain) |
observer.os.build |
ECS has observer.os.{family,full,kernel,name,platform,type,version} but not observer.os.build |
observer.id |
Not in ECS (ECS has observer.serial_number, observer.name, but not observer.id) |
observer.software_version |
Not in ECS |
observer.tychon_client_id |
Not in ECS — vendor-specific field, should be tychon.* |
observer.windows_server_role |
Not in ECS — vendor-specific field, should be tychon.* |
process.path |
Not in ECS (use process.executable) |
server.protocol |
Not in ECS — ECS server.* has no protocol sub-field |
Filestream boilerplate (same as tychon package, so given that they are there, I guess we have precedent and these could be allowed)
| Field | Reason |
|---|---|
input.type |
Not in ECS |
log.file.device_id |
Not in ECS |
log.file.fingerprint |
Not in ECS |
log.file.inode |
Not in ECS |
| on_failure: | ||
| - append: | ||
| field: error.pipeline | ||
| value: "Failed to parse certificate.not_before: {{_ingest.on_failure_message}}" |
There was a problem hiding this comment.
Please use the convention for error strings, for example here.
| on_failure: | ||
| - set: | ||
| field: tychon.pipeline.failed | ||
| value: true | ||
| - set: | ||
| field: error.message | ||
| value: "{{{ _ingest.on_failure_message }}}" | ||
| - set: | ||
| field: error.processor_type | ||
| value: "{{{ _ingest.on_failure_processor_type }}}" | ||
| - set: | ||
| field: error.processor_tag | ||
| value: "{{{ _ingest.on_failure_processor_tag }}}" | ||
| - set: | ||
| field: error.pipeline | ||
| value: "{{{ _ingest.on_failure_pipeline }}}" |
There was a problem hiding this comment.
Please use the conventional approach; example here.
There was a problem hiding this comment.
We updated the fatal pipeline on_failure path to emit the conventional processor/type/tag/pipeline/message string in error.message. We also removed the custom tychon.pipeline.failed flag and the separate error.processor_type / error.processor_tag fields from the emitted event and data stream mappings.
The recoverable date/convert sanitization warnings from the previous step remain in error.pipeline, because elastic-package treats populated error.message as an unexpected pipeline error for documents that were successfully sanitized and indexed. Fatal pipeline failures still use error.message.
|
@vera-review-bot review |
|
|
||
| - set: | ||
| field: data_stream.dataset | ||
| value: tychon_pqc |
There was a problem hiding this comment.
Severity: 🔴 Critical confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:133
The pipeline overwrites data_stream.dataset with 'tychon_pqc', but the real Fleet dataset is 'tychon_quantum_command.tychon_pqc' — drop both data_stream set processors so Fleet's own values stand.
Details
Fleet generates the index template for this data stream with data_stream.dataset mapped as constant_keyword whose value is tychon_quantum_command.tychon_pqc (the <package>.<data_stream> pair). This pipeline sets the field to the bare string tychon_pqc. Elasticsearch rejects any document whose constant_keyword value differs from the mapped value, so every event this pipeline processes fails to index.
The package contradicts itself on this point, which confirms the value here is the wrong one: data_stream/tychon_pqc/sample_event.json line 10 records "dataset": "tychon_quantum_command.tychon_pqc", all 14 transforms read from logs-tychon_quantum_command.tychon_pqc-*, and docs/README.md documents the stream as logs-tychon_quantum_command.tychon_pqc-<namespace>.
The data_stream.type: logs set processor immediately above (lines 127-129) is the same anti-pattern; it happens to match the mapped value today, so it is harmless but equally unnecessary. Package pipelines must never write data_stream.* — Fleet owns those fields.
Recommendation:
Delete both processors; Fleet populates data_stream.type, data_stream.dataset and data_stream.namespace from the policy.
# remove these two processors entirely
# - set:
# field: data_stream.type
# value: logs
#
# - set:
# field: data_stream.dataset
# value: tychon_pqcAdd a pipeline test (see the separate finding on missing tests) that asserts the emitted document carries data_stream.dataset: tychon_quantum_command.tychon_pqc.
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
There was a problem hiding this comment.
corrected pipeline overwriting.
There was a problem hiding this comment.
This also asks for a pipeline test.
| ignore_failure: true | ||
|
|
||
| - set: | ||
| field: event.ingested |
There was a problem hiding this comment.
Severity: 🟠 High confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:27
The pipeline sets event.ingested itself; remove the processor and let Fleet's final pipeline populate it.
Details
event.ingested is set by the Fleet-managed .fleet_final_pipeline, which runs after every package pipeline. Package pipelines must not set it themselves: the value written here is stamped at package-pipeline time rather than at final-ingest time, and the field is then overwritten or duplicated downstream depending on stack version. Integrations that set event.ingested in their own pipeline are treated as a standards violation across this repo.
This matters concretely for this package because the transforms use a time-based sync field; a package-controlled event.ingested makes that checkpoint semantics ambiguous.
Recommendation:
Delete the processor:
# remove:
# - set:
# field: event.ingested
# value: "{{_ingest.timestamp}}"Declare the field so it is still mapped and available to the transforms:
# data_stream/tychon_pqc/fields/ecs.yml
- name: event.ingested
external: ecs🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
There was a problem hiding this comment.
corrected. allowing Fleet pipeline to populate "event.ingested".
There was a problem hiding this comment.
This processor is still present.
| @@ -0,0 +1,46 @@ | |||
| title: Tychon Quantum Command | |||
There was a problem hiding this comment.
Severity: 🟠 High confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/manifest.yml:1
New data stream 'tychon_pqc' ships without pipeline tests; add _dev/test/pipeline fixtures covering the NDJSON record families the pipeline branches on.
Details
This PR adds a brand-new package with a single new data stream, and there is no _dev/ directory anywhere under data_stream/tychon_pqc/ — no _dev/test/pipeline/ inputs and no *-expected.json. Nothing in CI exercises the ingest pipeline.
That gap is why the data_stream.dataset bug (separate finding) and the event.dataset rewriting are unverified. The pipeline is large and heavily branched: five Painless scripts, a tychon.index switch that produces six different event.dataset values, 18 split processors, and certificate/cipher reconstruction blocks. None of those branches is covered.
A single fixture per tychon.index family (applications, certificates, ciphers, installed-apps, installed-browser-extensions, system-readiness) would pin the observable output of every branch the switch at lines 106-122 can take.
Recommendation:
Add, at minimum:
data_stream/tychon_pqc/_dev/test/pipeline/
test-common-config.yml
test-applications.log # one NDJSON record per line
test-applications.log-expected.json
test-certificates.log
test-certificates.log-expected.json
test-system-readiness.log
test-system-readiness.log-expected.json
With a test-common-config.yml such as:
fields:
tags:
- preserve_original_event
dynamic_fields:
event.ingested: ".*"Generate the expected files with elastic-package test pipeline --generate and commit them.
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| processors: | ||
| - set: | ||
| field: ecs.version | ||
| value: 8.17.0 |
There was a problem hiding this comment.
Severity: 🟠 High confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:6
The package has field files but no _dev/build/build.yml, so the hardcoded ecs.version 8.17.0 is pinned to nothing — add the build manifest with a matching ECS reference.
Details
The pipeline stamps ecs.version: 8.17.0 on every document, but the package ships no _dev/build/build.yml, so there is no ecs.reference pin anywhere. Two concrete consequences:
- Nothing validates that 8.17.0 is a real ECS release or that the field definitions in this package match it. The claim on every document is unbacked.
- Because ECS is not imported at build time, every ECS field had to be hand-redeclared in
data_stream/tychon_pqc/fields/ecs.yml(330 lines, noexternal: ecson any entry). Those hand-rolled definitions carry no ECS descriptions and will drift from ECS silently — and they are what let the non-ECS fields in theobserver.*/host.*/process.*namespaces slip in (separate finding).
Every package in this repo with field files carries a build manifest; this one does not.
Recommendation:
Add packages/tychon_quantum_command/_dev/build/build.yml pinned to the same ECS version the pipeline stamps:
dependencies:
ecs:
reference: "git@v8.17.0"Then convert the genuine ECS entries in fields/ecs.yml to references so descriptions and types come from ECS itself:
- name: host.ip
external: ecs
- name: host.hostname
external: ecs
- name: event.category
external: ecsIf you bump the reference later, update the pipeline's ecs.version value in the same commit so the two never disagree.
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| @@ -0,0 +1,44 @@ | |||
| - name: "@timestamp" | |||
There was a problem hiding this comment.
Severity: 🟠 High confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/fields/base-fields.yml:1
base-fields.yml contains custom root-level fields instead of the required base fields — move them into the tychon namespace and put the real base fields here.
Details
This file is named base-fields.yml but declares none of the base fields. It is missing data_stream.type, data_stream.dataset, data_stream.namespace, event.module and event.dataset, and the one base field it does have (@timestamp) is declared with a literal type instead of external: ecs.
What it contains instead is a set of custom fields declared at the document root: id, quantum_ready, quantum_ready_cert, quantum_ready_cipher, quantum_ready_kx, scan_type, scan.* and package.*. Two problems with that:
- Root-level generic names collide across the shared
logs-*data view.id,scan_typeandquantum_readyare exactly the kind of names another integration will also claim, producing mapping conflicts users cannot resolve. package.*is a real ECS field set (package.name,package.version,package.description,package.path). Declaringpackage.install_directoryalongside locally-typedpackage.name/package.versionputs vendor fields inside a reserved ECS namespace and detaches them from the ECS definitions.
Note id is also one of the latest.unique_key entries in all 14 transforms, so its declaration needs to be correct and stable.
Recommendation:
Replace the file contents with the standard base fields:
- name: data_stream.type
external: ecs
- name: data_stream.dataset
external: ecs
- name: data_stream.namespace
external: ecs
- name: event.module
type: constant_keyword
external: ecs
value: tychon_quantum_command
- name: event.dataset
type: constant_keyword
external: ecs
value: tychon_quantum_command.tychon_pqc
- name: '@timestamp'
external: ecsMove the custom fields into fields/fields.yml under the existing tychon group:
- name: tychon
type: group
fields:
- name: record_id
type: keyword
description: Stable TYCHON record identifier used as a transform unique key.
- name: quantum_ready
type: boolean
- name: scan
type: group
fields:
- name: type
type: keyword
- name: timestamp
type: dateIf you rename root id, update latest.unique_key in all 14 elasticsearch/transform/*/transform.yml files in the same commit.
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "description": "", | ||
| "id": "", | ||
| "params": { | ||
| "spec": "{\"$schema\": \"https://vega.github.io/schema/vega/v5.json\", \"padding\": {\"top\": 0, \"bottom\": 0, \"left\": 0, \"right\": 0}, \"background\": \"#111111\", \"signals\": [{\"name\": \"totalHosts\", \"update\": \"length(data('hosts_total'))>0 ? data('hosts_total')[0].n : 0\"}, {\"name\": \"osReady\", \"update\": \"length(data('os_pqc'))>0 ? data('os_pqc')[0].n : 0\"}, {\"name\": \"osPct\", \"update\": \"totalHosts > 0 ? round(osReady / totalHosts * 100) : 0\"}, {\"name\": \"osClr\", \"update\": \"osPct>=90 ? '#00c853' : osPct>=60 ? '#448aff' : osPct>=30 ? '#ffa726' : '#ef5350'\"}, {\"name\": \"kexReady\", \"update\": \"length(data('kex_pqc'))>0 ? data('kex_pqc')[0].n : 0\"}, {\"name\": \"kexPct\", \"update\": \"totalHosts > 0 ? round(kexReady / totalHosts * 100) : 0\"}, {\"name\": \"kexClr\", \"update\": \"kexPct>=90 ? '#00c853' : kexPct>=60 ? '#448aff' : kexPct>=30 ? '#ffa726' : '#ef5350'\"}, {\"name\": \"barW\", \"update\": \"width * 0.62 - 18\"}], \"data\": [{\"name\": \"hosts_raw\", \"url\": {\"%context%\": true, \"%timefield%\": \"@timestamp\", \"index\": \"tychon-pqc-inventory*\", \"body\": {\"size\": 0, \"aggs\": {\"v\": {\"cardinality\": {\"field\": \"host.id\"}}}}}, \"format\": {\"property\": \"aggregations.v\"}, \"transform\": [{\"type\": \"formula\", \"as\": \"n\", \"expr\": \"datum.value\"}]}, {\"name\": \"hosts_total\", \"source\": \"hosts_raw\"}, {\"name\": \"os_pqc_raw\", \"url\": {\"%context%\": true, \"%timefield%\": \"@timestamp\", \"index\": \"tychon-pqc-inventory*\", \"body\": {\"size\": 0, \"aggs\": {\"f\": {\"filter\": {\"term\": {\"host.os_pqc_tier\": \"PQC READY\"}}, \"aggs\": {\"u\": {\"cardinality\": {\"field\": \"host.id\"}}}}}}}, \"format\": {\"property\": \"aggregations.f.u\"}, \"transform\": [{\"type\": \"formula\", \"as\": \"n\", \"expr\": \"datum.value\"}]}, {\"name\": \"os_pqc\", \"source\": \"os_pqc_raw\"}, {\"name\": \"kex_pqc_raw\", \"url\": {\"%context%\": true, \"%timefield%\": \"@timestamp\", \"index\": \"tychon-pqc-inventory*\", \"body\": {\"size\": 0, \"aggs\": {\"f\": {\"filter\": {\"term\": {\"omb.kex_tier\": \"PQC READY\"}}, \"aggs\": {\"u\": {\"cardinality\": {\"field\": \"host.id\"}}}}}}}, \"format\": {\"property\": \"aggregations.f.u\"}, \"transform\": [{\"type\": \"formula\", \"as\": \"n\", \"expr\": \"datum.value\"}]}, {\"name\": \"kex_pqc\", \"source\": \"kex_pqc_raw\"}], \"marks\": [{\"type\": \"text\", \"encode\": {\"enter\": {\"x\": {\"value\": 16}, \"y\": {\"value\": 22}, \"text\": {\"value\": \"QUANTUM READINESS REPORT\"}, \"fill\": {\"value\": \"#cccccc\"}, \"fontSize\": {\"value\": 11}, \"fontWeight\": {\"value\": \"bold\"}, \"font\": {\"value\": \"monospace\"}, \"letterSpacing\": {\"value\": 1.5}}}}, {\"type\": \"text\", \"encode\": {\"enter\": {\"x\": {\"value\": 16}, \"y\": {\"value\": 40}, \"text\": {\"value\": \"PQC COMPLIANCE PROGRESS \\u2014 unique hosts at PQC READY tier\"}, \"fill\": {\"value\": \"#555555\"}, \"fontSize\": {\"value\": 9}, \"font\": {\"value\": \"monospace\"}, \"letterSpacing\": {\"value\": 1}}}}, {\"type\": \"rule\", \"encode\": {\"enter\": {\"x\": {\"value\": 0}, \"x2\": {\"signal\": \"width\"}, \"y\": {\"value\": 48}, \"stroke\": {\"value\": \"#252525\"}, \"strokeWidth\": {\"value\": 1}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 0}, \"y\": {\"value\": 60}, \"width\": {\"signal\": \"width\"}, \"height\": {\"value\": 78}, \"fill\": {\"value\": \"#161616\"}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 0}, \"y\": {\"value\": 60}, \"width\": {\"value\": 4}, \"height\": {\"value\": 78}, \"fill\": {\"signal\": \"osClr\"}}}}, {\"type\": \"text\", \"encode\": {\"enter\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 78}, \"text\": {\"value\": \"OS READINESS\"}, \"fill\": {\"value\": \"#888888\"}, \"fontSize\": {\"value\": 9}, \"fontWeight\": {\"value\": \"bold\"}, \"font\": {\"value\": \"monospace\"}, \"letterSpacing\": {\"value\": 1}}}}, {\"type\": \"text\", \"encode\": {\"update\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 93}, \"text\": {\"signal\": \"(osReady>=1000?format(osReady,'.3~s'):format(osReady,',')) + ' of ' + (totalHosts>=1000?format(totalHosts,'.3~s'):format(totalHosts,',')) + ' hosts'\"}, \"fill\": {\"value\": \"#444444\"}, \"fontSize\": {\"value\": 9}, \"font\": {\"value\": \"monospace\"}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 106}, \"width\": {\"signal\": \"barW\"}, \"height\": {\"value\": 8}, \"cornerRadius\": {\"value\": 4}, \"fill\": {\"value\": \"#1e1e1e\"}, \"stroke\": {\"value\": \"#2a2a2a\"}, \"strokeWidth\": {\"value\": 1}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 106}, \"width\": {\"signal\": \"max(0, barW * osPct / 100)\"}, \"height\": {\"value\": 8}, \"cornerRadius\": {\"value\": 4}, \"fill\": {\"signal\": \"osClr\"}}}}, {\"type\": \"text\", \"encode\": {\"update\": {\"x\": {\"signal\": \"width - 10\"}, \"y\": {\"value\": 122}, \"text\": {\"signal\": \"osPct + '%'\"}, \"fill\": {\"signal\": \"osClr\"}, \"fontSize\": {\"value\": 24}, \"fontWeight\": {\"value\": \"bold\"}, \"font\": {\"value\": \"monospace\"}, \"align\": {\"value\": \"right\"}}}}, {\"type\": \"rule\", \"encode\": {\"enter\": {\"x\": {\"value\": 0}, \"x2\": {\"signal\": \"width\"}, \"y\": {\"value\": 138}, \"stroke\": {\"value\": \"#222222\"}, \"strokeWidth\": {\"value\": 1}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 0}, \"y\": {\"value\": 140}, \"width\": {\"signal\": \"width\"}, \"height\": {\"value\": 78}, \"fill\": {\"value\": \"#161616\"}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 0}, \"y\": {\"value\": 140}, \"width\": {\"value\": 4}, \"height\": {\"value\": 78}, \"fill\": {\"signal\": \"kexClr\"}}}}, {\"type\": \"text\", \"encode\": {\"enter\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 158}, \"text\": {\"value\": \"KEY EXCHANGE\"}, \"fill\": {\"value\": \"#888888\"}, \"fontSize\": {\"value\": 9}, \"fontWeight\": {\"value\": \"bold\"}, \"font\": {\"value\": \"monospace\"}, \"letterSpacing\": {\"value\": 1}}}}, {\"type\": \"text\", \"encode\": {\"update\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 173}, \"text\": {\"signal\": \"(kexReady>=1000?format(kexReady,'.3~s'):format(kexReady,',')) + ' of ' + (totalHosts>=1000?format(totalHosts,'.3~s'):format(totalHosts,',')) + ' hosts'\"}, \"fill\": {\"value\": \"#444444\"}, \"fontSize\": {\"value\": 9}, \"font\": {\"value\": \"monospace\"}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 186}, \"width\": {\"signal\": \"barW\"}, \"height\": {\"value\": 8}, \"cornerRadius\": {\"value\": 4}, \"fill\": {\"value\": \"#1e1e1e\"}, \"stroke\": {\"value\": \"#2a2a2a\"}, \"strokeWidth\": {\"value\": 1}}}}, {\"type\": \"rect\", \"encode\": {\"update\": {\"x\": {\"value\": 18}, \"y\": {\"value\": 186}, \"width\": {\"signal\": \"max(0, barW * kexPct / 100)\"}, \"height\": {\"value\": 8}, \"cornerRadius\": {\"value\": 4}, \"fill\": {\"signal\": \"kexClr\"}}}}, {\"type\": \"text\", \"encode\": {\"update\": {\"x\": {\"signal\": \"width - 10\"}, \"y\": {\"value\": 202}, \"text\": {\"signal\": \"kexPct + '%'\"}, \"fill\": {\"signal\": \"kexClr\"}, \"fontSize\": {\"value\": 24}, \"fontWeight\": {\"value\": \"bold\"}, \"font\": {\"value\": \"monospace\"}, \"align\": {\"value\": \"right\"}}}}, {\"type\": \"text\", \"encode\": {\"update\": {\"x\": {\"signal\": \"width / 2\"}, \"y\": {\"signal\": \"height / 2 - 8\"}, \"text\": {\"signal\": \"length(data('hosts_raw')) === 0 ? 'NO DATA FOR CURRENT FILTERS / TIME RANGE' : ''\"}, \"fill\": {\"value\": \"#666666\"}, \"font\": {\"value\": \"monospace\"}, \"fontSize\": {\"value\": 11}, \"fontWeight\": {\"value\": \"bold\"}, \"align\": {\"value\": \"center\"}, \"baseline\": {\"value\": \"middle\"}, \"zindex\": {\"value\": 100}}}}, {\"type\": \"text\", \"encode\": {\"update\": {\"x\": {\"signal\": \"width / 2\"}, \"y\": {\"signal\": \"height / 2 + 12\"}, \"text\": {\"signal\": \"length(data('hosts_raw')) === 0 ? 'Adjust dashboard filters or expand the selected time range.' : ''\"}, \"fill\": {\"value\": \"#444444\"}, \"font\": {\"value\": \"monospace\"}, \"fontSize\": {\"value\": 9}, \"align\": {\"value\": \"center\"}, \"baseline\": {\"value\": \"middle\"}, \"zindex\": {\"value\": 100}}}}]}" |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: high path: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-32c01eb5-0d80-4a28-9de7-55b2046f7c45-inventory.json:108
Dashboard Vega panels query hardcoded 'tychon-pqc-*' indices with no data_stream.dataset filter — point them at the Fleet-managed pattern and scope them to this package's dataset.
Details
This Vega spec issues its Elasticsearch requests against "index": "tychon-pqc-inventory*" — an absolute index name that only exists if the transforms have run, that is not covered by any Fleet index template or data view, and that is not namespaced. The same pattern repeats across the dashboards: cost-analysis.json (tychon-pqc-system-readiness*), certificate-operations-dashboard.json (tychon-pqc-certificates*), application-connections-topology.json and application-report.json (tychon-pqc-applications).
Separately, grepping every file under kibana/ for data_stream.dataset returns no matches. No dashboard or saved search scopes its queries to this package's dataset, so any panel resolved through a broader data view will aggregate other integrations' documents alongside TYCHON's.
If the transform destinations are renamed to the data-stream convention (separate finding), these panels must be updated in the same change or every dashboard ships broken.
Recommendation:
Query the Fleet-managed pattern and filter to the package's dataset inside the Vega request body:
"url": {
"%context%": true,
"%timefield%": "@timestamp",
"index": "logs-tychon_quantum_command.inventory-*",
"body": {
"size": 0,
"query": {
"bool": {
"filter": [
{ "term": { "data_stream.dataset": "tychon_quantum_command.inventory" } }
]
}
},
"aggs": { "v": { "cardinality": { "field": "host.id" } } }
}
}For the non-Vega panels, add an equivalent filter to searchSourceJSON:
{
"meta": { "key": "data_stream.dataset", "type": "phrase", "negate": false, "disabled": false },
"query": { "match_phrase": { "data_stream.dataset": "tychon_quantum_command.tychon_pqc" } }
}🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "alias": null, | ||
| "disabled": false, | ||
| "field": "omb.kex_tier", | ||
| "index": "9d644013-9636-4968-9154-38f0c5207120", |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: high path: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-443e5928-b1c4-4e07-b0b9-c675dd057e2f-application-report.json:897
Two panel filters in the application report point at data-view ids that exist nowhere in the package, so those filters install broken — repoint them or add the matching references entries.
Details
The filter here sets "index": "9d644013-9636-4968-9154-38f0c5207120", and a second filter at line 1083 uses "7503da64-ec7e-41aa-962f-15507a9e77a5". Neither UUID appears anywhere else in the package: not in the three files under kibana/index_pattern/, not in this dashboard's references array, not in any other asset. They are leftovers from the authoring deployment.
On install, Kibana cannot resolve the data view behind these filters, so both render greyed-out/broken and the intended omb.kex_tier exclusion silently does not apply. The filters repeat at lines 968 and 1153.
Saved-object ids must be resolved through the references array so that Fleet can rewrite them at install time; embedding a raw id from the export environment never survives the move.
Recommendation:
Add a references entry for each filter and replace the literal id with the reference name:
{
"id": "<packaged-index-pattern-id>",
"name": "<panelIndex>:control_group_0:filter[0].meta.index",
"type": "index-pattern"
}The simplest fix is to re-export the dashboard from a clean Kibana where the panels were rebuilt against the packaged data view, so the ids in the panel state and the ids in references agree.
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "event": { | ||
| "kind": "event", | ||
| "category": ["configuration"], | ||
| "dataset": "tychon_quantum_command.tychon_pqc" |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/sample_event.json:6
sample_event.json is hand-written and does not match what the pipeline actually emits — regenerate it from a system test.
Details
This file records event.dataset: tychon_quantum_command.tychon_pqc and data_stream.dataset: tychon_quantum_command.tychon_pqc, but for a document with tychon.index: applications (line 20) the pipeline produces neither value: the dataset script rewrites event.dataset to tychon.application (default.yml line 107), and the set processor writes data_stream.dataset: tychon_pqc (default.yml line 133).
The file also carries no event.ingested, no host.id, no top-level id and no observer.id — and observer.id+id are the latest.unique_key of all 14 transforms, so the one document the package ships as representative would not produce a usable entity record.
A sample event must be produced by a real run so it stays an accurate description of the package's output. This one is documenting behaviour the package does not have, and it is rendered into docs/README.md for users.
Recommendation:
Generate it from a system test rather than writing it by hand:
cd packages/tychon_quantum_command
elastic-package test system --generateUntil a system test exists, keep the {{ event "tychon_pqc" }} directive in _dev/build/docs/README.md commented out and remove the hand-written file, rather than shipping a sample that contradicts the pipeline:
**Example event**
🤖 AI-Generated Review | Vera Review Bot | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
There was a problem hiding this comment.
sample_event.json generated with "elastic-package test system --generate" command
There was a problem hiding this comment.
How was this done? There is no system test.
Key changes:
- Reset package version to 0.1.0 and widened Kibana compatibility to >=8.11.0 <10.0.0.
- Added package-level _dev/build/build.yml with ECS git@v8.17.0.
- Kept transform destination indices as tychon-pqc-* and documented them as current-state upsert/entity indices keyed by observer.id + tychon.record.id.
- Kept the package event.ingested set processor. Elastic docs indicate _ingest.timestamp must be indexed via a set processor, and Fleet final pipeline behavior happens after package/
custom processing, so keeping it is the safer transform-sync path:
- https://www.elastic.co/guide/en/elasticsearch/reference/8.19/ingest.html
- https://www.elastic.co/docs/manage-data/ingest/transform-enrich/ingest-lag
- Converted unsafe Mustache set values to triple braces.
- Added processor tag values throughout the ingest pipeline.
- Moved raw/vendor x509 aliases under tychon.x509.*, while preserving normalized ECS-shaped x509.* fields.
- Fixed the two saved-object panel reference warnings.
- Regenerated pipeline expected outputs and replaced root sample_event.json with a real system-test event.
- Rebuilt generated docs and package artifact.
Validation run:
- elastic-package test pipeline --data-streams tychon_pqc: PASS
- elastic-package test system --data-streams tychon_pqc: PASS
- elastic-package build: PASS
- elastic-package check: PASS
system and pipeline tests were added. Can we get an updated review following our recent commit? |
efd6
left a comment
There was a problem hiding this comment.
There are still outstanding concerns. This change is very large, so to facilitate review, please do not resolve concerns unilaterally. If you intend to apply a fix to a concern, either mark it with a 👍 (or if complex, state what will be done), and if you reject a concern, explain why.
The major concerns I have at this stage is the absence of any tests and the non-conventional approach to mapping vendor fields; they should be under tychon_quantum_command.tychon_pqc based on the package and data stream name If this is too long (I think this is probably the case), then the filesystem names should be changed and the JSON path to match.
…yml:709:
- Date parse failures now remove the bad source field and derived copies:
- certificate.not_before, x509.not_before, tychon.certificate_leaf_details.validity.not_before
- certificate.not_after, x509.not_after, tychon.certificate_leaf_details.validity.not_after
- cipher.last_seen, tychon.cipher_negotiation.last_seen
- Convert failures now remove invalid numeric fields instead of silently leaving them:
- tychon.application.port
- tychon.application.port_quantum_grade.score
- Included pipeline and system test fixtures.
Added a focused fixture:
- data_stream/tychon_pqc/_dev/test/pipeline/test-invalid-typed-fields.log
- data_stream/tychon_pqc/_dev/test/pipeline/test-invalid-typed-fields.log-expected.json:15
Validation:
- elastic-package test pipeline --data-streams tychon_pqc -g: PASS
- elastic-package check: PASS
Refresh the package sample event and generated README from the successful lab output so the primary repository and mounted lab workspace remain aligned.
Declare tychon.x509.validity.not_before and not_after as date fields in every transform destination so the shared tychon-pqc data views do not combine date and keyword mappings.
Replace the unsupported date-valued Lens formula with last_value(cert_days_remaining) and remove its obsolete intermediate operations.
Map x509 and tychon.certificate validity fields as dates across transform destinations so cert_days_remaining and cert_total_days work over tychon-pqc wildcard indices.
Declare root x509.not_before and x509.not_after as date fields in the certificate transform so wildcard destination mappings remain consistent.
Remove the duplicate Time Left column reference introduced when replacing the unsupported date formula.
Define cert_days_remaining and cert_total_days on the tychon-pqc* data view used by Application Report Lens panels.
| if (ctx.certificate.issuer != null) { issuer.raw_string = ctx.certificate.issuer; } | ||
| if (!issuer.isEmpty()) { leafDetails.issuer = issuer; } | ||
| Map validity = [:]; | ||
| if (ctx.certificate.not_before != null) { validity.not_before = ctx.certificate.not_before; } |
There was a problem hiding this comment.
Severity: 🟠 High confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:767
tychon.certificate_leaf_details.validity.not_before/not_after still receive the raw certificate date string before the date processors normalise it, so an accepted non-ISO input (e.g. yyyy-MM-dd HH:mm:ss) reaches a date mapping as an unparseable string; extend the new sync script so the leaf-details copy also receives the normalised value.
Details
Prior finding 3e5f5c7e15def677 was only partially addressed. The reconstruct script (lines 766-770) copies ctx.certificate.not_before / not_after into tychon.certificate_leaf_details.validity.* as the raw string. date_certificate_not_before / date_certificate_not_after (lines 914-960) then normalise certificate.not_before / not_after in place, and the new script_sync_normalized_x509_certificate_dates (lines 962-980) re-syncs the normalised value only into x509.* and tychon.x509.*. tychon.certificate_leaf_details.validity.not_before / not_after are declared type: date in fields/fields.yml (lines 539-542). For an input in yyyy-MM-dd HH:mm:ss or MMM dd HH:mm:ss yyyy 'GMT' (both listed in formats), the date processor succeeds, the on_failure removal (lines 926-932) does not run, and the leaf-details field keeps a string that the default strict_date_optional_time||epoch_millis mapping cannot parse, so the whole document is rejected at index time. The existing test-x509-date-normalization.json fixture feeds exactly this shape (certificate.not_before: "2025-01-01 00:00:00").
Recommendation:
Extend the sync script so the leaf-details copy also receives the normalised value (and run it whenever certificate is a Map, not only when x509 exists):
- script:
tag: script_sync_normalized_x509_certificate_dates
lang: painless
description: Sync normalized certificate dates into ECS x509 fields and the independent TYCHON copies.
if: ctx.certificate instanceof Map || ctx.x509 instanceof Map
source: >
if (ctx.tychon == null || !(ctx.tychon instanceof Map)) { ctx.tychon = [:]; }
if (ctx.certificate instanceof Map) {
if (ctx.tychon.certificate_leaf_details instanceof Map && ctx.tychon.certificate_leaf_details.validity instanceof Map) {
if (ctx.certificate.not_before != null) { ctx.tychon.certificate_leaf_details.validity.not_before = ctx.certificate.not_before; }
if (ctx.certificate.not_after != null) { ctx.tychon.certificate_leaf_details.validity.not_after = ctx.certificate.not_after; }
}
if (ctx.x509 instanceof Map) {
if (ctx.certificate.not_before != null) { ctx.x509.not_before = ctx.certificate.not_before; }
if (ctx.certificate.not_after != null) { ctx.x509.not_after = ctx.certificate.not_after; }
}
}
if (ctx.x509 instanceof Map) {
if (ctx.tychon.x509 == null || !(ctx.tychon.x509 instanceof Map)) { ctx.tychon.x509 = [:]; }
if (ctx.x509.not_before != null) { ctx.tychon.x509.not_before = ctx.x509.not_before; }
if (ctx.x509.not_after != null) { ctx.tychon.x509.not_after = ctx.x509.not_after; }
if (ctx.x509.validity instanceof Map && !ctx.x509.validity.isEmpty()) {
Map validityCopy = [:];
for (validityEntry in ctx.x509.validity.entrySet()) {
validityCopy[validityEntry.getKey()] = validityEntry.getValue();
}
ctx.tychon.x509.validity = validityCopy;
}
}Then regenerate test-x509-date-normalization.json expectations so the leaf-details copy is pinned as a normalised date.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| if (ctx.tychon == null || !(ctx.tychon instanceof Map)) { | ||
| ctx.tychon = [:]; | ||
| } | ||
| for (String root : ['asset_type', 'certificate', 'config', 'crypto', 'error', 'ipsec_tunnel', 'kerberos', 'keystore', 'migration_priority', 'omb', 'pipeline', 'port', 'pqc', 'pqc_readiness', 'quantum_readiness', 'quantum_risk', 'scan_mode', 'scanner_version', 'security', 'ssh', 'target_host', 'tls', 'tunnel_details', 'type', 'vulnerability', 'vpn_client', 'vpn_config']) { |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:1156
Root cipher.* is copied into tychon.cipher_negotiation but never removed or lifted, so it survives to the index as an undeclared non-ECS root object; remove the root object after date_cipher_last_seen (or add cipher to the lift list).
Details
script_reconstruct_tychon_cipher_negotiation_from_cipher_fie (lines 790-814) copies every ctx.cipher.* leaf into tychon.cipher_negotiation, and date_cipher_last_seen (lines 982-1001) normalises cipher.last_seen in place. Unlike certificate, kerberos, tls and the other vendor roots, cipher is absent from the lift_remaining_tqc_vendor_roots list on line 1156, and no remove processor targets it (the cleanup at lines 499-505 only drops id, scan, scan_type and the quantum_ready* keys). fields.yml declares no root cipher group (only tychon.cipher and tychon.cipher_negotiation), so a record carrying cipher.* is indexed with a dynamically mapped root cipher object alongside the vendor copy. This is one more instance of the non-ECS root namespace issue the maintainers are tracking, but cipher is not in their table and no fixture carries a valid cipher.* value (the only occurrence is the invalid cipher.last_seen in test-invalid-typed-fields.log, which on_failure removes), so the pipeline tests cannot surface it.
Recommendation:
Drop the root object once the vendor copy is complete and the date is normalised. Writing the normalised date straight into the vendor copy also removes the pre-normalisation raw copy:
- date:
tag: date_cipher_last_seen
field: cipher.last_seen
target_field: tychon.cipher_negotiation.last_seen
formats:
- ISO8601
- yyyy-MM-dd'T'HH:mm:ssXXX
- yyyy-MM-dd'T'HH:mm:ss.SSSXXX
if: ctx.cipher?.last_seen != null
on_failure:
- remove:
tag: remove_failed_cipher_last_seen_fields
field:
- tychon.cipher_negotiation.last_seen
ignore_missing: true
- append:
tag: append_error_pipeline_date_cipher_last_seen
field: error.pipeline
value: "Processor {{{_ingest.on_failure_processor_type}}} with tag {{{_ingest.on_failure_processor_tag}}} failed with message: {{{_ingest.on_failure_message}}}"
- remove:
tag: remove_root_cipher
field: cipher
ignore_missing: trueAdd a fixture record with a valid cipher.cipher_suite, cipher.protocol and cipher.last_seen so the reconstruct path and the absence of a root cipher object are pinned.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| @@ -0,0 +1 @@ | |||
| {"@timestamp":"2026-07-06T17:03:00.055778Z","event.action":"non_tls_cipher_detected","event.category":"network","event.dataset":"tychon.non_tls_cipher","id":"e95601f097b201be","kerberos.config_source":"os_default","kerberos.has_aes128":true,"kerberos.has_aes256":true,"kerberos.has_des":false,"kerberos.has_rc4":true,"kerberos.is_explicitly_configured":false,"kerberos.is_quantum_safe":false,"kerberos.raw_bitmask":28,"kerberos.supported_types":"RC4-HMAC, AES128-CTS-HMAC-SHA1-96, AES256-CTS-HMAC-SHA1-96","observer.bigfix_client_installed":false,"observer.bios_serial_number":"Synthetic Test BIOS 0001","observer.cpu_cores":2,"observer.cpu_logical_cores":2,"observer.cpu_model_name":"Intel(R) Xeon(R) CPU E5-2683 v4 @ 2.10GHz","observer.cpu_vendor_id":"GenuineIntel","observer.current_user":"example.test\\test-user","observer.domain":"example.test","observer.fips_mode_enabled":false,"observer.hostname":"test-host-01","observer.id":"00000000-0000-4000-8000-000000000002","observer.ip_addresses":"2001:db8::1, 192.0.2.30, 192.0.2.10, 2001:db8::2, 192.0.2.20","observer.is_vdi_environment":false,"observer.kernel_arch":"x86_64","observer.kernel_version":"26100.8655","observer.machine_serial_number":"TEST-VM-SERIAL-0001","observer.organization":"example.test","observer.os.build":"26100","observer.os.family":"windows","observer.os.kernel":"10.0","observer.os.name":"windows","observer.os.platform":"Microsoft Windows 11 Pro","observer.os.version":"10.0.26100.8655","observer.platform_version":"8655","observer.ram_used_percent":39,"observer.software_version":"2.0.4.10","observer.system_uptime_seconds":1725864,"observer.total_ram_bytes":17178578944,"observer.tychon_client_id":"11111111-1111-4111-8111-111111111111","observer.user_gid":"S-1-5-21-0000000000-0000000000-0000000000-1001","observer.user_home_dir":"C:\\Users\\test-user","observer.user_uid":"S-1-5-21-0000000000-0000000000-0000000000-1000","observer.vdi_identity_source":"gopsutil","observer.windows_server_role":"workstation","scan.target_input":"localhost","scan.timestamp":"2026-07-06T17:03:00.055778Z","scan.type":"local","tychon.cipher.config_source":"registry_os_default","tychon.cipher.insecure_ciphers":"RC4-HMAC","tychon.cipher.is_encrypted":true,"tychon.cipher.migration_priority":"critical","tychon.cipher.port":88,"tychon.cipher.pqc_readiness":"vulnerable","tychon.cipher.pqc_vulnerable":true,"tychon.cipher.protocol":"Kerberos","tychon.cipher.quantum_risk":"critical","tychon.cipher.recommended_action":"Remove DES/RC4 from SupportedEncryptionTypes via Group Policy","tychon.cipher.supported_ciphers":"AES128-CTS-HMAC-SHA1-96,AES256-CTS-HMAC-SHA1-96","tychon.crypto.cipher":"AES128-CTS-HMAC-SHA1-96","tychon.crypto.pqc_readiness":"vulnerable","tychon.crypto.pqc_vulnerable":true,"tychon.crypto.protocol":"Kerberos","tychon.crypto.quantum_risk":"critical","tychon.index":"ciphers","tychon.type":"cipher"} | |||
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/_dev/test/pipeline/test-ciphers.log:1
Several pipeline branches still have no fixture (valid root cipher.* records with intel.vulnerabilities, the tls.supported_ciphers/weak_ciphers and tychon.cipher_quick.* splits, tychon.installed_app.crypto_libraries, the quantum_assessment.app_group instance_count default and the vendor timestamp fallback); add small targeted records so their output is pinned.
Details
The fixture set now covers all 14 tychon.index families plus routing, related.ip, x509 date normalisation, malformed JSON and the tychon.raw agent path, so prior findings 130a66160968cdcc, 0bfd0fb561f42d77 and f9c11b02ef378120 are addressed. The cipher.* part of prior finding 2ac4f189c128da72 is not: grepping every handwritten fixture and _dev/deploy/docker/sample.ndjson finds no record with cipher.cipher_suite or cipher.intel.vulnerabilities (so script_reconstruct_tychon_cipher_negotiation_from_cipher_fie on a valid record and script_convert_cipher_vulnerability_strings_into_arrays never run; the only root cipher.* input is the invalid cipher.last_seen in test-invalid-typed-fields.log), no tls.supported_ciphers, tls.weak_ciphers or tychon.cipher_quick.* values (test-ciphers.log uses tychon.cipher.*/tychon.crypto.*; sample.ndjson line 10 carries tls.insecure_ciphers/supported_protocols/supported_key_exchanges only), no tychon.installed_app.crypto_libraries, no event.dataset: quantum_assessment.app_group record with quantum_readiness.cost_analysis, and no record using the vendor timestamp key handled at default.yml lines 55-56 and 91-96. These branches are the ones most likely to regress silently when the pipeline is reworked for the open ECS-namespace thread; elastic-package only validates what the fixtures exercise.
Recommendation:
Append one or two anonymised records that drive these branches (to the existing family fixtures or a new test-ciphers-leaf.log), then regenerate with elastic-package test pipeline --data-streams tychon_pqc --generate. For example:
{"timestamp":"2026-07-06T17:03:10.055778Z","event.category":"network","event.dataset":"tychon.non_tls_cipher","event.type":"info","id":"cipher-leaf-test-record-1","observer.id":"00000000-0000-4000-8000-000000000002","observer.hostname":"test-host-01","cipher.cipher_suite":"TLS_RSA_WITH_3DES_EDE_CBC_SHA","cipher.protocol":"TLSv1.2","cipher.key_length_bits":112,"cipher.last_seen":"2026-07-06T17:03:10Z","cipher.intel.vulnerabilities":"SWEET32, no-forward-secrecy","tls.supported_ciphers":"TLS_AES_256_GCM_SHA384, TLS_RSA_WITH_3DES_EDE_CBC_SHA","tls.weak_ciphers":"TLS_RSA_WITH_3DES_EDE_CBC_SHA","tychon.cipher_quick.supported_protocols":"TLSv1.2, TLSv1.3","tychon.cipher_quick.insecure_ciphers":"TLS_RSA_WITH_3DES_EDE_CBC_SHA","tychon.index":"ciphers","tychon.type":"cipher"}
{"@timestamp":"2026-07-06T17:03:11.055778Z","event.category":"configuration","event.dataset":"quantum_assessment.app_group","event.type":"info","id":"app-group-test-record-1","observer.id":"00000000-0000-4000-8000-000000000002","quantum_readiness.cost_analysis.total_cost_usd":1200,"quantum_readiness.cost_analysis.total_labor_hours":8,"tychon.index":"system-readiness","tychon.type":"system_readiness"}
and, in test-installed-apps.log, a record with "tychon.installed_app.crypto_libraries":"openssl, bcrypt.dll".
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "id": "", | ||
| "params": { | ||
| "fontSize": 12, | ||
| "markdown": "[Inventory](/app/dashboards#/view/tychon_quantum_command-32c01eb5-0d80-4a28-9de7-55b2046f7c45-inventory) | [Application Report](/app/dashboards#/view/tychon_quantum_command-443e5928-b1c4-4e07-b0b9-c675dd057e2f-application-report) | [Application Detail](/app/dashboards#/view/tychon_quantum_command-6dfff015-3cc9-48b6-9410-7d8c01ff0d9a-application-detail) | [Certificate Report](/app/dashboards#/view/tychon_quantum_command-d0159137-9139-4a93-85bb-2ac9ddab3982-certificate-operations-dashboard) | [Application Connections Topology](/app/dashboards#/view/tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology) | Cost Analysis", |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-02366033-dee4-4ea4-8458-7c8a8b58987e-cost-analysis.json:52
The navigation markdown panel on every dashboard links with root-absolute /app/dashboards#/view/<id> URLs, which drop the Kibana basePath and the current space prefix, so the links 404 or land in the wrong space on any deployment that is not default-space with no basePath; use a dashboard-native Links panel instead.
Details
Each of the six dashboards opens with a hidden-title markdown visualization (panelIndex tychon-quantum-command-nav, line 52 in every file) whose links are hardcoded as /app/dashboards#/view/tychon_quantum_command-.... The markdown vis renders these as ordinary anchors resolved against the origin, so a Kibana served under server.basePath (e.g. /kibana) or opened inside a non-default space (/s/<space>/app/...) is sent to a path without the prefix. Fleet installs package assets into the space where the integration is added, so in that common case the link either 404s or resolves to the default space where the dashboard does not exist. The manifest floor (^8.14.0) already supports the Links panel type, which resolves targets through the dashboard references array and therefore builds URLs with the correct basePath and space.
Recommendation:
Replace the markdown nav panel with a by-value Links panel whose links[].destinationRefName entries resolve through the dashboard references array. For example:
{
"type": "links",
"embeddableConfig": {
"attributes": {
"layout": "horizontal",
"links": [
{"id": "nav-inventory", "type": "dashboardLink", "label": "Inventory", "destinationRefName": "link_nav-inventory_dashboard", "order": 0},
{"id": "nav-app-report", "type": "dashboardLink", "label": "Application Report", "destinationRefName": "link_nav-app-report_dashboard", "order": 1}
]
}
}
}with matching { "type": "dashboard", "name": "<panelIndex>:link_nav-inventory_dashboard", "id": "tychon_quantum_command-32c01eb5-...-inventory" } entries in references. Build the panel in Kibana and re-export with elastic-package export dashboards so the reference names are generated correctly.
Also in: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-32c01eb5-0d80-4a28-9de7-55b2046f7c45-inventory.json:52, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-443e5928-b1c4-4e07-b0b9-c675dd057e2f-application-report.json:52, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-6dfff015-3cc9-48b6-9410-7d8c01ff0d9a-application-detail.json:52, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology.json:52, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-d0159137-9139-4a93-85bb-2ac9ddab3982-certificate-operations-dashboard.json:52
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| if (ctx.certificate.sha1_fingerprint != null) { leafDetails.sha1_fingerprint = ctx.certificate.sha1_fingerprint; } | ||
| if (ctx.certificate.subject_key_id != null) { leafDetails.subject_key_id = ctx.certificate.subject_key_id; } | ||
| if (ctx.certificate.pqc_vulnerable != null) { leafDetails.pqc_vulnerable = ctx.certificate.pqc_vulnerable; } | ||
| if (ctx.certificate.raw_pem_certificate != null) { leafDetails.raw_pem_certificate = ctx.certificate.raw_pem_certificate; } |
There was a problem hiding this comment.
Severity: 🔵 Low confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:786
Every certificate record is stored twice: the reconstruct script copies all certificate.* leaves (including the full PEM) into tychon.certificate_leaf_details, and the lift script then moves the same certificate object wholesale to tychon.certificate; keep one copy, or at least exclude raw_pem_certificate from one of them.
Details
Lines 743-788 build tychon.certificate_leaf_details from ctx.certificate (subject, issuer, validity, serial, signature, raw_pem_certificate, fingerprints, ...) without removing anything from ctx.certificate. Line 1156 then lists certificate in lift_remaining_tqc_vendor_roots, so the untouched map is moved to tychon.certificate. fields.yml declares raw_pem_certificate as match_only_text under both groups (lines 456 and 755), confirming both copies are intended to be indexed. For certificate-family records this doubles _source size and indexing work, with the PEM blob the largest contributor.
Recommendation:
Either drop certificate from the lift list and remove the root object once the reconstruct script has run, or stop reconstructing certificate_leaf_details if tychon.certificate is the intended home (repointing dashboards and transform field files accordingly). If both shapes must exist for compatibility, exclude the PEM from one of them:
if (ctx.certificate.raw_pem_certificate != null) { leafDetails.raw_pem_certificate = ctx.certificate.raw_pem_certificate; ctx.certificate.remove('raw_pem_certificate'); }
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| @@ -0,0 +1,13 @@ | |||
| service: tychon_quantum_command | |||
There was a problem hiding this comment.
Severity: 🔵 Low confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/_dev/test/system/test-default-config.yml:1
The system test config has no assert.hit_count, so the test passes once a single one of the 14 sample.ndjson lines is indexed; assert the full count as the sibling tychon package does, and consider bounding wait_for_data_timeout.
Details
_dev/deploy/docker/docker-compose.yml copies the 14-line sample.ndjson (one record per tychon.index family) to {{SERVICE_LOGS_DIR}}/tqc.ndjson, and the config only points the filestream input at that file. Without assert.hit_count, elastic-package accepts the run as soon as at least one document lands, so a mapping rejection or pipeline drop affecting 13 of the 14 families (the failure mode the maintainers' ECS-namespace thread is concerned with) still yields a green system test. Every system test in the sibling packages/tychon package sets assert.hit_count. Without wait_for_data_timeout the runner waits its default (10m) before reporting a broken run.
Recommendation:
Assert the full fixture count and, optionally, bound the wait:
service: tychon_quantum_command
input: filestream
wait_for_data_timeout: 3m
vars: ~
data_stream:
vars:
paths:
- "{{SERVICE_LOGS_DIR}}/tqc.ndjson"
windows_paths: []
linux_paths: []
preserve_original_event: false
tags:
- tychon
- quantum
assert:
hit_count: 14🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
|
/test |
| ignore_missing: true | ||
| if: ctx.event != null && ctx.event.original != null | ||
|
|
||
| on_failure: |
There was a problem hiding this comment.
Please add the append to tags requested in #20142 (comment).
There was a problem hiding this comment.
We added preserve_original_event to the JSON parser’s on_failure path with duplicate protection. The top-level pipeline failure handler already had the same behavior.
| "tychon": { | ||
| "error": { | ||
| "pipeline": [ |
There was a problem hiding this comment.
Why are you putting this here?
There was a problem hiding this comment.
We removed the malformed-JSON tychon.error.pipeline output from the expected fixture. Parse failures now use ECS error.message; the vendor-specific error is no longer emitted for this case.
There was a problem hiding this comment.
This appears to have come back. Please deleted it.
| - set: | ||
| tag: preserve_malformed_json_message | ||
| field: event.original | ||
| copy_from: message | ||
| override: false | ||
| ignore_empty_value: true |
There was a problem hiding this comment.
Why are you doing this conditionally on failure? If a user wants to keep the original event they cannot under this model.
There was a problem hiding this comment.
We moved the event.original copy before JSON parsing and gated it on the user’s preserve_original_event setting. This should preserve the raw message even when parsing succeeds or
fails.
|
✅ All changelog entries have the correct PR link. |
💔 Build Failed
Failed CI StepsHistory
|
| field: timestamp | ||
| target_field: "@timestamp" | ||
| ignore_missing: true | ||
| ignore_failure: true |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:107
On the agent path a vendor timestamp key is copied to the root by the lift script and rename_timestamp then fails silently because @timestamp already exists, leaving an undeclared root timestamp field and discarding the vendor time; decide the precedence explicitly and remove the leftover key.
Details
The lift script only applies raw.timestamp to @timestamp when @timestamp is null (line 66); otherwise it falls through to ctx[key] = value (line 89) and writes timestamp at the document root. In production the filestream input always sets @timestamp (read time) and the ndjson parser places the record under tychon.raw, so this fall-through is the normal branch for any record carrying timestamp. The following rename_timestamp (lines 102-107) then fails with field [@timestamp] already exists and ignore_failure: true hides that, so timestamp survives to the index as a root field that is neither ECS nor declared in fields.yml (only nested scan.timestamp at line 179 and tychon.*.timestamp at line 1100 are declared) and is not in the lift_remaining_tqc_vendor_roots list (line 1182). The .log pipeline fixtures never show this because they carry no agent @timestamp: test-branch-coverage.log line 1 has timestamp alone, so the rename succeeds there. Net effect on the agent path: the vendor event time is replaced by the agent read time and an unmapped root field is created. Whether real TQC output ever emits timestamp rather than @timestamp is not determinable from the source (all 14 sample.ndjson records use @timestamp), so confidence is medium.
Recommendation:
Make the vendor time win (or explicitly decide it should not) and never leave the key behind. In the lift script prefer the record's own timestamps:
if (key == '@timestamp') {
ctx['@timestamp'] = value;
} else if (key == 'timestamp') {
if (ctx['@timestamp'] == null || !raw.containsKey('@timestamp')) {
ctx['@timestamp'] = value;
}
} else if (key == 'tychon') {
and replace the blind rename with a guarded rename plus cleanup so nothing is left at the root:
- rename:
tag: rename_timestamp
field: timestamp
target_field: "@timestamp"
ignore_missing: true
if: ctx['@timestamp'] == null
- remove:
tag: remove_timestamp
field: timestamp
ignore_missing: trueAdd a tychon.raw fixture record that carries timestamp alongside an agent @timestamp so the chosen precedence is pinned.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| { | ||
| "events": [ | ||
| { | ||
| "message": "{ malformed-json" |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/_dev/test/pipeline/test-malformed-json.json:4
The malformed-JSON fixture only runs with the preserve_original_event tag injected by test-common-config.yml, so the production-default handling of a bad line (no tag, message removed) is never pinned; add a per-test config that mirrors the default agent tags.
Details
test-common-config.yml injects tags: [preserve_original_event] into every fixture, and the preserve_original_event set processor (default.yml lines 9-15) copies message into event.original before the json processor runs. For the one malformed record this means the scenario always exercises the retained-original branch, while the manifest default and the system test (test-default-config.yml) both ship preserve_original_event: false with tags tychon/quantum. Under that default the pipeline currently strips message via remove_message (line 1240) once the scripts have created ctx.tychon, leaving the malformed line with no payload. That behaviour, and its correct replacement once the json failure handling is fixed, is what this fixture should lock down. elastic-package uses a test-specific <fixture>-config.yml in place of the common config when one exists, so a small dedicated config covers the production path without touching the other fixtures.
Recommendation:
Add test-malformed-json.json-config.yml next to the fixture so the record is processed with the agent's default tags rather than the test-only preserve tag, then regenerate the expected output:
fields:
tags:
- tychon
- quantumIf the retained-original branch should also stay pinned, add a second malformed record to test-invalid-typed-fields.log (which keeps the common config) instead of relying on this fixture for both.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "description": "All certs — FILE (disk scan) and PORT (live TLS). Sorted by earliest expiry. Scales via server-side pagination.", | ||
| "kibanaSavedObjectMeta": { | ||
| "searchSourceJSON": { | ||
| "filter": [], |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/kibana/search/tychon_quantum_command-d7e8f9a0-2b3c-4d5e-9f0a-b1c2d3e40001-certificate-inventory-detail.json:23
The "Certificate Inventory Detail" saved search embedded in the Certificate Operations dashboard queries the tychon-pqc-* data view with an empty filter, so it lists every transform destination record (applications, ciphers, inventory, keystores, ...) rather than certificates; add a filter that keeps only certificate-bearing records.
Details
The search references data view 1dc9d581-4b38-4108-84e1-59a9fbcfbca5, whose title is tychon-pqc-* (kibana/index_pattern/1dc9d581-....json line 11), which matches all 14 transform destination indices (tychon-pqc-applications, tychon-pqc-ciphers, tychon-pqc-inventory, ...). searchSourceJSON.filter is [] and the query is empty (lines 23-29), and the serialized tab-level copy at line 60 is the same. The Certificate Operations dashboard embeds this search by reference (dashboard references line 452) and its Vega panels scope themselves to tychon-pqc-certificates* (plus tychon-pqc-inventory* with a tychon.type term for the source-type panel), so the table is the only panel that is not scoped and will show rows with no certificate columns populated. The dashboard-level event.dataset filter does not narrow by family. Sorting by the runtime field cert_days_remaining ascending pushes those rows to the end but does not remove them, and they still consume the server-side pages the description advertises.
Recommendation:
Add a filter to both kibanaSavedObjectMeta.searchSourceJSON blocks so only certificate-bearing records are returned, for example a KQL query:
"query": {
"language": "kuery",
"query": "tychon.certificate.not_after : * or x509.not_after : *"
}or, if the table is meant to be certificates-only, point the search at a tychon-pqc-certificates* data view like the Vega panels. Re-export the search with elastic-package export dashboards afterwards so the tab-level copy stays in sync.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| field: routing | ||
| target_field: tychon.routing | ||
| ignore_missing: true | ||
| if: ctx?.routing != null && ctx?.tychon?.routing == null |
There was a problem hiding this comment.
Severity: 🔵 Low confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:682
rename_routing_to_tychon_routing is skipped when tychon.routing already exists, and routing is no longer in the lift list, so a record carrying both shapes keeps an undeclared root routing object; merge or remove the root copy instead of skipping.
Details
The condition ctx?.routing != null && ctx?.tychon?.routing == null means that when a record already has tychon.routing.* (from the raw-path lift script or dotted tychon.routing.* keys) and also a root routing.* block, the root object is left untouched. routing was removed from the lift_remaining_tqc_vendor_roots list (line 1182) when this rename was introduced, so nothing later relocates or deletes it, and root routing is not declared in any fields file (only tychon.routing at fields.yml line 269). This gap follows from the condition suggested in prior finding 54ac7c2e4f3cf8ba, which fixed the ordering problem but did not cover the both-shapes case; this refines that advice rather than contradicting it. Low because no fixture or sample record carries both shapes.
Recommendation:
Either put routing back in the lift list (the lift script already merges maps key-by-key when the vendor copy exists), or add a follow-up remove:
- remove:
tag: remove_root_routing
field: routing
ignore_missing: true
if: ctx.routing != null && ctx.tychon?.routing != null🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "hideChart": false, | ||
| "isTextBasedQuery": false, | ||
| "kibanaSavedObjectMeta": { | ||
| "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"tychon.type\":\"exists\",\"key\":\"tychon.omb.vulnerability_status\",\"value\":\"exists\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"exists\":{\"field\":\"tychon.omb.vulnerability_status\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" |
There was a problem hiding this comment.
Severity: 🔵 Low confidence: high path: packages/tychon_quantum_command/kibana/search/tychon_quantum_command-662602a4-f820-4e80-9fe2-115c951fe43c-dod-omb-report.json:126
The tab-level filter in the "DoD OMB Report" saved search has its meta.type key mis-renamed to tychon.type (a stray vendor-namespace search-and-replace), so the filter pill loses its type and renders as a custom filter; restore "type":"exists".
Details
The top-level filter at lines 50-58 correctly has "type": "exists" in meta. The serialized tabs[0].attributes.kibanaSavedObjectMeta.searchSourceJSON string at line 126 instead contains "tychon.type":"exists" inside the same meta object. tychon.type is a real field in this package (used as a Vega aggregation field and search column), which is how a global rename of type to tychon.type produced this. On Kibana versions that read the tabs block (typeMigrationVersion 10.9.0), the exists filter still executes via its query block, but the pill has no meta.type and is shown and edited as a custom DSL filter instead of an exists filter. A maintainer (efd6) previously asked for all saved objects to be re-exported with elastic-package, which would also regenerate this block.
Recommendation:
Correct the key in the serialized tab filter meta so it matches the top-level copy, or re-export the search with elastic-package export dashboards.
| "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"tychon.type\":\"exists\",\"key\":\"tychon.omb.vulnerability_status\",\"value\":\"exists\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"exists\":{\"field\":\"tychon.omb.vulnerability_status\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" | |
| "searchSourceJSON": "{\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filter\":[{\"meta\":{\"alias\":null,\"negate\":false,\"disabled\":false,\"type\":\"exists\",\"key\":\"tychon.omb.vulnerability_status\",\"value\":\"exists\",\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.filter[0].meta.index\"},\"query\":{\"exists\":{\"field\":\"tychon.omb.vulnerability_status\"}},\"$state\":{\"store\":\"appState\"}}],\"indexRefName\":\"kibanaSavedObjectMeta.searchSourceJSON.index\"}" |
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| field: message | ||
| add_to_root: true | ||
| if: ctx.tychon == null && ctx.message != null | ||
| ignore_failure: true |
There was a problem hiding this comment.
Severity: 🟠 High confidence: high path: packages/tychon_quantum_command/data_stream/tychon_pqc/elasticsearch/ingest_pipeline/default.yml:22
The json processor sets both ignore_failure: true and a processor-level on_failure; ignore_failure wins, so the handler never runs and a malformed line is indexed as a normal event.kind: event document with no error.message. Drop ignore_failure (or drop the local handler and rely on the pipeline-level on_failure).
Details
Verified against the current source. In Elasticsearch's CompoundProcessor a processor that throws with ignore_failure: true has its exception discarded and execution continues with the next processor; the processor's on_failure list is only consulted when ignore_failure is false. The json_message processor (lines 17-44) sets both, so initialize_tychon_json_message, append_error_message_json_message, set_pipeline_error_to_event_kind_json_message and append_preserve_original_event_tag_json_message are unreachable. For the fixture _dev/test/pipeline/test-malformed-json.json (message: "{ malformed-json", run with the default tychon/quantum tags from its per-test config): json fails silently, ctx.tychon stays null, the later set processors still stamp event.kind: event, event.category and event.dataset, and neither remove_message (line 1257, requires ctx.tychon != null) nor remove_message_2 (line 1263, requires event.original) fires. The document is indexed as a normal categorised event with the raw text in message, no error.message, no pipeline_error kind and no preserve_original_event tag. Prior finding 441829c2981a631c asked for a decode failure to reach the pipeline-level on_failure (or, if a local handler is kept, for it to append error.message and set pipeline_error); the current handler has the right shape but is disabled by the added ignore_failure.
Recommendation:
Remove ignore_failure: true so the local handler runs, or remove the local handler entirely and rely on the pipeline-level on_failure (lines 1265-1281), which already does the same three things:
- json:
tag: json_message
field: message
add_to_root: true
if: ctx.tychon == null && ctx.message != null
on_failure:
- set:
tag: initialize_tychon_json_message
field: tychon
value: {}
override: false
- append:
tag: append_error_message_json_message
field: error.message
value: |-
Processor '{{{ _ingest.on_failure_processor_type }}}'
{{{#_ingest.on_failure_processor_tag}}}with tag '{{{ _ingest.on_failure_processor_tag }}}'
{{{/_ingest.on_failure_processor_tag}}}failed with message '{{{ _ingest.on_failure_message }}}'
- set:
tag: set_pipeline_error_to_event_kind_json_message
field: event.kind
value: pipeline_error
- append:
tag: append_preserve_original_event_tag_json_message
field: tags
value: preserve_original_event
allow_duplicates: falseThen regenerate the expected output for test-malformed-json.json so the pipeline_error path is pinned.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| ignore_missing: true | ||
| {{/if}} | ||
| {{#if processors}} | ||
| {{processors}} |
There was a problem hiding this comment.
Severity: 🟠 High confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/agent/stream/stream.yml.hbs:46
The {{processors}} passthrough renders at column 0 under a processors list whose fixed items are indented two spaces, so a user-supplied Processors value produces mixed-indentation YAML that fails to parse; put the built-in items at column 0.
Details
Fleet compiles a type: yaml variable by replacing the root-level (column 0) placeholder with the YAML dump of the value, which emits list items at column 0. In this template processors: already holds - add_locale: ~ and the conditional - copy_fields: at indent 2 (lines 36-44), and {{processors}} follows at indent 0 (line 46). With the manifest's processors var set (declared at data_stream/tychon_pqc/manifest.yml line 50, show_user: false), the rendered stream becomes:
processors:
- add_locale: ~
- drop_fields:
fields: [x]A block sequence cannot change indentation mid-list, so the policy fails to compile and the input does not start. Templates that combine fixed processors with the passthrough (for example packages/system/data_stream/auth/agent/stream/log.yml.hbs lines 40-45) put the built-in items at column 0 so they line up with the injected block. A handful of other packages ship the same indent-2 shape, which suggests the case is rarely exercised, not that it renders correctly. The system test (_dev/test/system/test-default-config.yml) does not set processors, so CI does not cover it. This was introduced while addressing prior finding 6c916638640616bc, whose recommendation showed only the var and the {{#if processors}} block.
Recommendation:
De-indent the fixed processor items so they match the column-0 output of the yaml var:
processors:
- add_locale: ~
{{#if preserve_original_event}}
- copy_fields:
fields:
- from: message
to: event.original
fail_on_error: false
ignore_missing: true
{{/if}}
{{#if processors}}
{{processors}}
{{/if}}Optionally add a system test variant that sets a processors value so the rendered policy is validated in CI.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| type: ip | ||
| - name: ipv4 | ||
| type: ip | ||
| - name: tychon.tls |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/fields/fields.yml:1450
The pipeline splits tls.previous_supported_{protocols,ciphers,key_exchanges} (lifted to tychon.tls.*) and tychon.tags, but none of these four fields is declared in any field file; declare them under the tychon groups or drop the dead split processors.
Details
Verified: default.yml has split processors split_tls_previous_supported_protocols / _ciphers / _key_exchanges (lines 617-633) and split_tychon_tags (lines 711-715). The tls root is moved under tychon.tls by lift_remaining_tqc_vendor_roots (line 1195 includes 'tls'), so the resulting paths are tychon.tls.previous_supported_protocols, tychon.tls.previous_supported_ciphers, tychon.tls.previous_supported_key_exchanges and tychon.tags. The tychon.tls group here (lines 1450-1521) declares supported_protocols, supported_ciphers and supported_key_exchanges but no previous_* leaves; a package-wide search for previous_supported matches only the pipeline, and no field file declares a tags leaf under tychon (only ECS tags in ecs.yml). No pipeline fixture carries these keys, so the gap is invisible to the pipeline tests today, but any real record emitting them lands as an undeclared field (dynamic mapping in the source stream, keyword-only via strings_as_keyword in the transform destinations) and would fail field validation the moment a fixture includes them. Whether TQC still emits these keys could not be determined from the repository (see the unresolved question).
Recommendation:
Either declare the fields the pipeline produces, or remove the split processors if TQC no longer emits these keys. To declare them, extend the tychon.tls group and add a tags leaf under the top-level tychon group (mirroring in the transform field files that carry tychon.tls):
- name: tychon.tls
type: group
fields:
- name: previous_supported_ciphers
type: keyword
description: Cipher suites supported by the target in the previous TQC scan.
- name: previous_supported_key_exchanges
type: keyword
description: Key exchange algorithms supported by the target in the previous TQC scan.
- name: previous_supported_protocols
type: keyword
description: TLS protocol versions supported by the target in the previous TQC scan.and under the top-level tychon group:
- name: tags
type: keyword
description: Vendor tags attached to the TQC record.Then add a fixture record carrying these keys so the mapping is pinned by the pipeline tests.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| - data_frozen | ||
| - data_cold | ||
| dest: | ||
| index: tychon-pqc-applications |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/elasticsearch/transform/applications/transform.yml:16
The 14 destination indices carry no version suffix and no alias, so a future mapping change cannot be rolled out without breaking the dashboards; add a version suffix to dest.index and a move_on_creation alias for consumers.
Details
Verified: every transform writes straight to a bare, unversioned name (this one to tychon-pqc-applications, readiness/transform.yml to tychon-pqc-system-readiness, and so on) and defines no dest.aliases. The dashboards query these concrete names (tychon-pqc-inventory*, tychon-pqc-system-readiness*, tychon-pqc-certificates*, tychon-pqc*). When a breaking mapping change to a destination is needed later, the only options are to reuse the same index name (mapping conflict against the existing index) or rename it and repoint every dashboard. The sibling tychon package avoids this with a versioned dest.index (for example packages/tychon/elasticsearch/transform/host/transform.yml line 18, logs-tychon_latest.dest_host-2) plus a stable alias with move_on_creation: true (lines 19-21), which is the pattern the Kibana assets should query. This complements prior finding 9af2cffee49e8246 (destination naming convention) rather than replacing it: whatever base name is chosen, it should be versioned and fronted by an alias.
Recommendation:
Version the destination and expose a stable alias, then point the Kibana assets at the alias (repeat for all 14 transforms):
dest:
index: "logs-tychon_quantum_command_latest.dest_applications-1"
aliases:
- alias: "logs-tychon_quantum_command_latest.applications"
move_on_creation: trueAlso in: packages/tychon_quantum_command/elasticsearch/transform/archives/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/assets/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/browser_exts/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/certificates/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/ciphers/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/crypto_libs/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/inst_apps/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/inventory/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/ipsec_tnls/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/keystores/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/macsec/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/readiness/transform.yml:16, packages/tychon_quantum_command/elasticsearch/transform/vpn_clients/transform.yml:16
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "description": "", | ||
| "id": "", | ||
| "params": { | ||
| "spec": "{\"$schema\":\"https://vega.github.io/schema/vega/v5.json\",\"config\":{\"kibana\":{\"restoreSignalValuesOnRefresh\":true}},\"description\":\"PQC Upgrade Cost Analysis \\u2014 Responsive KPI header: unified top card with accent stripe, three cost-breakdown tiles, and proportional composition bar. Reads pre-computed fields from tychon-pqc-system-readiness*. No cost arithmetic in Vega.\",\"autosize\":{\"type\":\"fit\",\"contains\":\"padding\"},\"padding\":{\"left\":16,\"right\":16,\"top\":16,\"bottom\":16},\"data\":[{\"name\":\"cost_totals\",\"url\":{\"%context%\":true,\"%timefield%\":\"@timestamp\",\"index\":\"tychon-pqc-system-readiness*\",\"body\":{\"size\":0,\"aggs\":{\"agg_labor_hours\":{\"sum\":{\"field\":\"tychon.quantum_readiness.cost_analysis.total_labor_hours\"}},\"agg_total_cost\":{\"sum\":{\"field\":\"tychon.quantum_readiness.cost_analysis.total_cost_usd\"}},\"agg_labor_cost\":{\"sum\":{\"field\":\"tychon.quantum_readiness.cost_analysis.total_labor_cost_usd\"}},\"agg_hw_cost\":{\"sum\":{\"field\":\"tychon.quantum_readiness.cost_analysis.total_hardware_cost_usd\"}},\"agg_lic_cost\":{\"sum\":{\"field\":\"tychon.quantum_readiness.cost_analysis.total_license_cost_usd\"}},\"agg_asset_count\":{\"value_count\":{\"field\":\"tychon.quantum_readiness.cost_analysis.total_cost_usd\"}}}}},\"format\":{\"property\":\"aggregations\"},\"transform\":[{\"type\":\"formula\",\"as\":\"labor_hours\",\"expr\":\"isValid(datum.agg_labor_hours) ? datum.agg_labor_hours.value : 0\"},{\"type\":\"formula\",\"as\":\"total_cost\",\"expr\":\"isValid(datum.agg_total_cost) ? datum.agg_total_cost.value : 0\"},{\"type\":\"formula\",\"as\":\"labor_cost\",\"expr\":\"isValid(datum.agg_labor_cost) ? datum.agg_labor_cost.value : 0\"},{\"type\":\"formula\",\"as\":\"hw_cost\",\"expr\":\"isValid(datum.agg_hw_cost) ? datum.agg_hw_cost.value : 0\"},{\"type\":\"formula\",\"as\":\"lic_cost\",\"expr\":\"isValid(datum.agg_lic_cost) ? datum.agg_lic_cost.value : 0\"},{\"type\":\"formula\",\"as\":\"asset_count\",\"expr\":\"isValid(datum.agg_asset_count) ? datum.agg_asset_count.value : 0\"}]}],\"signals\":[{\"name\":\"gap\",\"value\":12},{\"name\":\"topH\",\"value\":124},{\"name\":\"midH\",\"value\":88},{\"name\":\"midY\",\"update\":\"topH + gap\"},{\"name\":\"cw\",\"update\":\"(width - gap * 2) / 3\"},{\"name\":\"c2x\",\"update\":\"cw + gap\"},{\"name\":\"c3x\",\"update\":\"(cw + gap) * 2\"},{\"name\":\"div1x\",\"update\":\"width / 3\"},{\"name\":\"div2x\",\"update\":\"width * 2 / 3\"},{\"name\":\"r\",\"update\":\"length(data('cost_totals')) > 0 ? data('cost_totals')[0] : {total_cost:0,labor_hours:0,labor_cost:0,hw_cost:0,lic_cost:0,asset_count:0}\"}],\"marks\":[{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"value\":0},\"y\":{\"value\":0},\"width\":{\"signal\":\"width\"},\"height\":{\"signal\":\"topH\"},\"fill\":{\"value\":\"#f8faff\"},\"stroke\":{\"value\":\"#dbeafe\"},\"strokeWidth\":{\"value\":1.5},\"cornerRadius\":{\"value\":10}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"value\":0},\"y\":{\"value\":0},\"width\":{\"signal\":\"width\"},\"height\":{\"value\":4},\"fill\":{\"value\":\"#3b82f6\"},\"cornerRadiusTopLeft\":{\"value\":10},\"cornerRadiusTopRight\":{\"value\":10}}}},{\"type\":\"rule\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x\"},\"y\":{\"value\":18},\"x2\":{\"signal\":\"div1x\"},\"y2\":{\"signal\":\"topH - 18\"},\"stroke\":{\"value\":\"#e2e8f0\"},\"strokeWidth\":{\"value\":1}}}},{\"type\":\"rule\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div2x\"},\"y\":{\"value\":18},\"x2\":{\"signal\":\"div2x\"},\"y2\":{\"signal\":\"topH - 18\"},\"stroke\":{\"value\":\"#e2e8f0\"},\"strokeWidth\":{\"value\":1}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x / 2\"},\"y\":{\"signal\":\"topH * 0.40\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":38},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#1d4ed8\"},\"text\":{\"signal\":\"'$' + format(r.total_cost, ',.0f')\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x / 2\"},\"y\":{\"signal\":\"topH * 0.65\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":12},\"fill\":{\"value\":\"#64748b\"},\"text\":{\"value\":\"Total Upgrade Cost\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x / 2\"},\"y\":{\"signal\":\"topH * 0.85\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":10},\"fill\":{\"value\":\"#94a3b8\"},\"text\":{\"signal\":\"r.asset_count > 0 ? '$' + format(r.total_cost / r.asset_count, ',.0f') + ' per asset' : ''\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x + (div2x - div1x) / 2\"},\"y\":{\"signal\":\"topH * 0.40\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":34},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#047857\"},\"text\":{\"signal\":\"format(r.labor_hours, ',.1f') + ' h'\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x + (div2x - div1x) / 2\"},\"y\":{\"signal\":\"topH * 0.65\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":12},\"fill\":{\"value\":\"#64748b\"},\"text\":{\"value\":\"Total Labor Hours\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div1x + (div2x - div1x) / 2\"},\"y\":{\"signal\":\"topH * 0.85\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":10},\"fill\":{\"value\":\"#94a3b8\"},\"text\":{\"signal\":\"r.asset_count > 0 ? format(r.labor_hours / r.asset_count, '.1f') + ' h per asset' : ''\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div2x + (width - div2x) / 2\"},\"y\":{\"signal\":\"topH * 0.40\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":34},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#7e22ce\"},\"text\":{\"signal\":\"format(r.asset_count, ',')\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"div2x + (width - div2x) / 2\"},\"y\":{\"signal\":\"topH * 0.65\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":12},\"fill\":{\"value\":\"#64748b\"},\"text\":{\"value\":\"Assets Requiring Upgrade\"}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"value\":0},\"y\":{\"signal\":\"midY\"},\"width\":{\"signal\":\"cw\"},\"height\":{\"signal\":\"midH\"},\"fill\":{\"value\":\"#eff6ff\"},\"stroke\":{\"value\":\"#bfdbfe\"},\"strokeWidth\":{\"value\":1},\"cornerRadius\":{\"value\":8}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"value\":0},\"y\":{\"signal\":\"midY\"},\"width\":{\"value\":5},\"height\":{\"signal\":\"midH\"},\"fill\":{\"value\":\"#3b82f6\"},\"cornerRadiusTopLeft\":{\"value\":8},\"cornerRadiusBottomLeft\":{\"value\":8}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.34\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":26},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#1d4ed8\"},\"text\":{\"signal\":\"'$' + format(r.labor_cost, ',.0f')\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.58\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":11},\"fill\":{\"value\":\"#374151\"},\"text\":{\"value\":\"Labor Cost\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.78\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":10},\"fill\":{\"value\":\"#9ca3af\"},\"text\":{\"signal\":\"r.total_cost > 0 ? format(r.labor_cost / r.total_cost * 100, '.0f') + '% of total' : ''\"}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c2x\"},\"y\":{\"signal\":\"midY\"},\"width\":{\"signal\":\"cw\"},\"height\":{\"signal\":\"midH\"},\"fill\":{\"value\":\"#fff1f2\"},\"stroke\":{\"value\":\"#fca5a5\"},\"strokeWidth\":{\"value\":1},\"cornerRadius\":{\"value\":8}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c2x\"},\"y\":{\"signal\":\"midY\"},\"width\":{\"value\":5},\"height\":{\"signal\":\"midH\"},\"fill\":{\"value\":\"#ef4444\"},\"cornerRadiusTopLeft\":{\"value\":8},\"cornerRadiusBottomLeft\":{\"value\":8}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c2x + cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.34\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":26},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#b91c1c\"},\"text\":{\"signal\":\"'$' + format(r.hw_cost, ',.0f')\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c2x + cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.58\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":11},\"fill\":{\"value\":\"#374151\"},\"text\":{\"value\":\"Hardware Cost\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c2x + cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.78\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":10},\"fill\":{\"value\":\"#9ca3af\"},\"text\":{\"signal\":\"r.total_cost > 0 ? format(r.hw_cost / r.total_cost * 100, '.0f') + '% of total' : ''\"}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c3x\"},\"y\":{\"signal\":\"midY\"},\"width\":{\"signal\":\"cw\"},\"height\":{\"signal\":\"midH\"},\"fill\":{\"value\":\"#fffbeb\"},\"stroke\":{\"value\":\"#fcd34d\"},\"strokeWidth\":{\"value\":1},\"cornerRadius\":{\"value\":8}}}},{\"type\":\"rect\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c3x\"},\"y\":{\"signal\":\"midY\"},\"width\":{\"value\":5},\"height\":{\"signal\":\"midH\"},\"fill\":{\"value\":\"#f59e0b\"},\"cornerRadiusTopLeft\":{\"value\":8},\"cornerRadiusBottomLeft\":{\"value\":8}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c3x + cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.34\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":26},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#b45309\"},\"text\":{\"signal\":\"'$' + format(r.lic_cost, ',.0f')\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c3x + cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.58\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":11},\"fill\":{\"value\":\"#374151\"},\"text\":{\"value\":\"License / Software Cost\"}}}},{\"type\":\"text\",\"encode\":{\"enter\":{\"x\":{\"signal\":\"c3x + cw / 2\"},\"y\":{\"signal\":\"midY + midH * 0.78\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"fontSize\":{\"value\":10},\"fill\":{\"value\":\"#9ca3af\"},\"text\":{\"signal\":\"r.total_cost > 0 ? format(r.lic_cost / r.total_cost * 100, '.0f') + '% of total' : ''\"}}}},{\"type\":\"text\",\"encode\":{\"update\":{\"x\":{\"signal\":\"width / 2\"},\"y\":{\"signal\":\"height / 2 - 8\"},\"text\":{\"signal\":\"length(data('cost_totals')) === 0 ? 'NO DATA FOR CURRENT FILTERS / TIME RANGE' : ''\"},\"fill\":{\"value\":\"#666666\"},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":11},\"fontWeight\":{\"value\":\"bold\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"zindex\":{\"value\":100}}}},{\"type\":\"text\",\"encode\":{\"update\":{\"x\":{\"signal\":\"width / 2\"},\"y\":{\"signal\":\"height / 2 + 12\"},\"text\":{\"signal\":\"length(data('cost_totals')) === 0 ? 'Adjust dashboard filters or expand the selected time range.' : ''\"},\"fill\":{\"value\":\"#444444\"},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":9},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"zindex\":{\"value\":100}}}}]}" |
There was a problem hiding this comment.
Severity: 🟡 Medium confidence: medium path: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-02366033-dee4-4ea4-8458-7c8a8b58987e-cost-analysis.json:97
Two defects in the Cost Analysis KPI header: (1) its sums run over every system-readiness record with no tychon.record.dataset filter, so per-host and app-group rows are added together and "Assets Requiring Upgrade" counts app-group rows; (2) like ten other Vega panels, its no-data overlay tests length(data(...)) === 0 on a single-object data source that always yields one row, so the overlay can never appear. Scope the header to quantum_assessment records and test the returned value or hits.total instead of the row count.
Details
Both issues sit on the same panel spec, so they are reported together.
Unfiltered header totals. The cost_totals data source runs sum over tychon.quantum_readiness.cost_analysis.total_cost_usd, total_labor_hours, total_labor_cost_usd, total_hardware_cost_usd, total_license_cost_usd and a value_count of total_cost_usd against tychon-pqc-system-readiness* with no record-type filter. The readiness transform (elasticsearch/transform/readiness/transform.yml) copies every record with tychon.index: system-readiness into that index, and the fixtures show two record shapes landing there: the per-host quantum_assessment record (_dev/test/pipeline/test-system-readiness.log) and the quantum_assessment.app_group record (_dev/test/pipeline/test-branch-coverage.log line 3), both carrying quantum_readiness.cost_analysis.total_cost_usd / total_labor_hours. The other Vega panels on this dashboard wrap their aggregations in a filter on tychon.record.dataset (qa_only on line 151 and 205, app_only on line 205); the header is the only one that does not. So "Total Upgrade Cost" and "Total Labor Hours" mix host-level and app-group-level totals, "Assets Requiring Upgrade" counts one per app-group row rather than one per asset, and the derived per-asset figures are wrong. Whether the per-host total already includes app-group costs could not be determined from the repository; either way the header is inconsistent with its sibling panels.
Unreachable empty state. A size: 0 aggregation request always returns an aggregations object, and metric aggregations (sum, value_count, cardinality, filter) always return a value even when no documents match. When format.property selects that object (aggregations, aggregations.v, aggregations.f), Vega wraps it as a one-element array and the following transforms are formulas only, so length(data('cost_totals')) === 0 is always false and the 'NO DATA FOR CURRENT FILTERS / TIME RANGE' text never renders. Verified panels wired this way: Cost Analysis cost_totals (line 97); Inventory hosts_raw (lines 97 and 151, aggregations.v); Application Report apps_raw (line 120, aggregations.v); Application Connections Topology context (line 176, aggregations, whose flatten runs over a constant key/value list and so still yields rows), apps_raw (line 233) and risk (line 289); Certificate Operations d_total (line 82, aggregations.v), raw (lines 154 and 334, aggregations) and d_fs (line 370, aggregations.v). The panels that select a .buckets array, or flatten a buckets array (for example the Cost Analysis bubble panel on line 205, which the original candidate listed in error), do produce zero rows and their check works. This is the mechanism used to address the maintainer's request for empty-state indicators, so about a third of the panels still silently render zeros.
Recommendation:
For the header, filter to the per-host assessment records and count assets on an identity field rather than on the cost value; for the empty state, keep the hit count available and test that instead of the row count. Combined for cost_totals:
"url": {
"%context%": true,
"%timefield%": "@timestamp",
"index": "tychon-pqc-system-readiness*",
"body": {
"size": 0,
"track_total_hits": true,
"aggs": {
"qa_only": {
"filter": {"term": {"tychon.record.dataset": "quantum_assessment"}},
"aggs": {
"agg_labor_hours": {"sum": {"field": "tychon.quantum_readiness.cost_analysis.total_labor_hours"}},
"agg_total_cost": {"sum": {"field": "tychon.quantum_readiness.cost_analysis.total_cost_usd"}},
"agg_labor_cost": {"sum": {"field": "tychon.quantum_readiness.cost_analysis.total_labor_cost_usd"}},
"agg_hw_cost": {"sum": {"field": "tychon.quantum_readiness.cost_analysis.total_hardware_cost_usd"}},
"agg_lic_cost": {"sum": {"field": "tychon.quantum_readiness.cost_analysis.total_license_cost_usd"}},
"agg_asset_count": {"cardinality": {"field": "observer.id"}}
}
}
}
}
},
"format": {"property": ""},
"transform": [
{"type": "formula", "as": "hits", "expr": "isValid(datum.hits) && isValid(datum.hits.total) ? datum.hits.total.value : 0"},
{"type": "formula", "as": "total_cost", "expr": "isValid(datum.aggregations.qa_only.agg_total_cost) ? datum.aggregations.qa_only.agg_total_cost.value : 0"}
]and drive the overlay with data('cost_totals')[0].hits === 0. For the other single-object panels, either apply the same track_total_hits pattern or test the metric itself (for example data('d_total')[0].n === 0). If the app-group totals are meant to be included in the headline, document that and exclude them from the asset count instead.
Also in: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-32c01eb5-0d80-4a28-9de7-55b2046f7c45-inventory.json:97, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-32c01eb5-0d80-4a28-9de7-55b2046f7c45-inventory.json:151, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-443e5928-b1c4-4e07-b0b9-c675dd057e2f-application-report.json:120, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology.json:176, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology.json:233, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology.json:289, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-d0159137-9139-4a93-85bb-2ac9ddab3982-certificate-operations-dashboard.json:82, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-d0159137-9139-4a93-85bb-2ac9ddab3982-certificate-operations-dashboard.json:154, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-d0159137-9139-4a93-85bb-2ac9ddab3982-certificate-operations-dashboard.json:334, packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-d0159137-9139-4a93-85bb-2ac9ddab3982-certificate-operations-dashboard.json:370
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| "description": "", | ||
| "id": "", | ||
| "params": { | ||
| "spec": "{\"$schema\":\"https://vega.github.io/schema/vega/v5.json\",\"config\":{\"kibana\":{\"restoreSignalValuesOnRefresh\":true}},\"description\":\"Selection details panel for host/application context using dashboard filters.\",\"autosize\":\"fit\",\"padding\":10,\"background\":\"#000000\",\"signals\":[{\"name\":\"panelW\",\"update\":\"width - 20\"},{\"name\":\"labelX\",\"value\":26},{\"name\":\"valueX\",\"update\":\"width * 0.42\"},{\"name\":\"row0\",\"value\":74},{\"name\":\"rowH\",\"value\":24}],\"data\":[{\"name\":\"context\",\"url\":{\"%context%\":true,\"%timefield%\":\"@timestamp\",\"index\":\"tychon-pqc*\",\"body\":{\"size\":0,\"aggs\":{\"host\":{\"terms\":{\"field\":\"observer.hostname\",\"size\":1}},\"app\":{\"terms\":{\"field\":\"tychon.application.name\",\"size\":1}},\"dst\":{\"terms\":{\"field\":\"server.address\",\"size\":1}},\"proto\":{\"terms\":{\"field\":\"network.protocol\",\"size\":1}},\"tls_ver\":{\"terms\":{\"field\":\"tychon.tls.preferred_protocol\",\"size\":1}},\"cipher\":{\"terms\":{\"field\":\"tychon.tls.preferred_cipher\",\"size\":1}},\"events\":{\"value_count\":{\"field\":\"@timestamp\"}},\"first_seen\":{\"min\":{\"field\":\"@timestamp\"}},\"last_seen\":{\"max\":{\"field\":\"@timestamp\"}}}}},\"format\":{\"property\":\"aggregations\"},\"transform\":[{\"type\":\"formula\",\"as\":\"host\",\"expr\":\"datum.host && datum.host.buckets && length(datum.host.buckets)>0 ? datum.host.buckets[0].key : ''\"},{\"type\":\"formula\",\"as\":\"app\",\"expr\":\"datum.app && datum.app.buckets && length(datum.app.buckets)>0 ? datum.app.buckets[0].key : ''\"},{\"type\":\"formula\",\"as\":\"dst\",\"expr\":\"datum.dst && datum.dst.buckets && length(datum.dst.buckets)>0 ? datum.dst.buckets[0].key : ''\"},{\"type\":\"formula\",\"as\":\"proto\",\"expr\":\"datum.proto && datum.proto.buckets && length(datum.proto.buckets)>0 ? datum.proto.buckets[0].key : ''\"},{\"type\":\"formula\",\"as\":\"tlsVer\",\"expr\":\"datum.tls_ver && datum.tls_ver.buckets && length(datum.tls_ver.buckets)>0 ? datum.tls_ver.buckets[0].key : ''\"},{\"type\":\"formula\",\"as\":\"cipher\",\"expr\":\"datum.cipher && datum.cipher.buckets && length(datum.cipher.buckets)>0 ? datum.cipher.buckets[0].key : ''\"},{\"type\":\"formula\",\"as\":\"events\",\"expr\":\"datum.events ? datum.events.value : 0\"},{\"type\":\"formula\",\"as\":\"firstSeen\",\"expr\":\"datum.first_seen && isValid(datum.first_seen.value_as_string) ? datum.first_seen.value_as_string : ''\"},{\"type\":\"formula\",\"as\":\"lastSeen\",\"expr\":\"datum.last_seen && isValid(datum.last_seen.value_as_string) ? datum.last_seen.value_as_string : ''\"},{\"type\":\"formula\",\"as\":\"selectionType\",\"expr\":\"datum.app != '' ? 'APPLICATION CONTEXT' : (datum.host != '' ? 'HOST CONTEXT' : 'NO SELECTION')\"},{\"type\":\"formula\",\"as\":\"selectionId\",\"expr\":\"datum.app != '' ? datum.app : (datum.host != '' ? datum.host : 'Select a host/app in the graph')\"}]},{\"name\":\"rows\",\"source\":\"context\",\"transform\":[{\"type\":\"project\",\"fields\":[\"selectionType\",\"selectionId\",\"host\",\"app\",\"dst\",\"proto\",\"tlsVer\",\"cipher\",\"events\",\"firstSeen\",\"lastSeen\"],\"as\":[\"selectionType\",\"selectionId\",\"host\",\"app\",\"dst\",\"proto\",\"tlsVer\",\"cipher\",\"events\",\"firstSeen\",\"lastSeen\"]},{\"type\":\"formula\",\"as\":\"kv\",\"expr\":\"[{k:'Context',v:datum.selectionType},{k:'Selection',v:datum.selectionId},{k:'Source Host',v:datum.host},{k:'Application',v:datum.app},{k:'Destination',v:datum.dst},{k:'Protocol',v:datum.proto},{k:'TLS Version',v:datum.tlsVer},{k:'Cipher',v:datum.cipher},{k:'Event Count',v:format(datum.events, ',')},{k:'First Seen',v:datum.firstSeen},{k:'Last Seen',v:datum.lastSeen}]\"},{\"type\":\"flatten\",\"fields\":[\"kv\"],\"as\":[\"row\"]},{\"type\":\"window\",\"ops\":[\"row_number\"],\"as\":[\"rn\"]},{\"type\":\"formula\",\"as\":\"y\",\"expr\":\"row0 + (datum.rn - 1) * rowH\"}]}],\"marks\":[{\"type\":\"rect\",\"encode\":{\"update\":{\"x\":{\"value\":10},\"y\":{\"value\":10},\"x2\":{\"signal\":\"width - 10\"},\"y2\":{\"signal\":\"height - 10\"},\"fill\":{\"value\":\"#0f1115\"},\"fillOpacity\":{\"value\":0.96},\"stroke\":{\"value\":\"#2b3440\"},\"strokeWidth\":{\"value\":1.2},\"cornerRadius\":{\"value\":8}}}},{\"type\":\"rect\",\"encode\":{\"update\":{\"x\":{\"value\":10},\"y\":{\"value\":10},\"x2\":{\"signal\":\"width - 10\"},\"y2\":{\"value\":42},\"fill\":{\"value\":\"#17324a\"},\"fillOpacity\":{\"value\":0.92},\"cornerRadiusTopLeft\":{\"value\":8},\"cornerRadiusTopRight\":{\"value\":8}}}},{\"type\":\"text\",\"encode\":{\"update\":{\"x\":{\"value\":24},\"y\":{\"value\":30},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":12},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#e8f3ff\"},\"text\":{\"value\":\"SELECTION DETAILS\"},\"baseline\":{\"value\":\"middle\"}}}},{\"type\":\"rule\",\"encode\":{\"update\":{\"x\":{\"signal\":\"valueX - 10\"},\"y\":{\"value\":54},\"y2\":{\"signal\":\"height - 20\"},\"stroke\":{\"value\":\"#1f2a36\"},\"strokeWidth\":{\"value\":1}}}},{\"type\":\"text\",\"from\":{\"data\":\"rows\"},\"encode\":{\"update\":{\"x\":{\"signal\":\"labelX\"},\"y\":{\"field\":\"y\"},\"text\":{\"signal\":\"datum.row.k\"},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":10},\"fontWeight\":{\"value\":\"bold\"},\"fill\":{\"value\":\"#9fc4e0\"},\"baseline\":{\"value\":\"middle\"}}}},{\"type\":\"text\",\"from\":{\"data\":\"rows\"},\"encode\":{\"update\":{\"x\":{\"signal\":\"valueX\"},\"y\":{\"field\":\"y\"},\"text\":{\"signal\":\"datum.row.v == '' ? '\\u2014' : datum.row.v\"},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":10},\"fill\":{\"value\":\"#e8eef5\"},\"baseline\":{\"value\":\"middle\"},\"limit\":{\"signal\":\"width - valueX - 18\"}}}},{\"type\":\"text\",\"encode\":{\"update\":{\"x\":{\"signal\":\"width / 2\"},\"y\":{\"signal\":\"height / 2 - 8\"},\"text\":{\"signal\":\"length(data('context')) === 0 ? 'NO DATA FOR CURRENT FILTERS / TIME RANGE' : ''\"},\"fill\":{\"value\":\"#666666\"},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":11},\"fontWeight\":{\"value\":\"bold\"},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"zindex\":{\"value\":100}}}},{\"type\":\"text\",\"encode\":{\"update\":{\"x\":{\"signal\":\"width / 2\"},\"y\":{\"signal\":\"height / 2 + 12\"},\"text\":{\"signal\":\"length(data('context')) === 0 ? 'Adjust dashboard filters or expand the selected time range.' : ''\"},\"fill\":{\"value\":\"#444444\"},\"font\":{\"value\":\"monospace\"},\"fontSize\":{\"value\":9},\"align\":{\"value\":\"center\"},\"baseline\":{\"value\":\"middle\"},\"zindex\":{\"value\":100}}}}]}" |
There was a problem hiding this comment.
Severity: 🔵 Low confidence: medium path: packages/tychon_quantum_command/kibana/dashboard/tychon_quantum_command-6f3d60d5-b5fb-45a5-9298-acf3ceb3ea1b-application-connections-topology.json:176
The "Connections Selection Details" panel derives its context from size-1 terms aggregations, so with no host or application filter applied it presents the single most frequent application as "APPLICATION CONTEXT" and the "NO SELECTION" state is only reachable when the index is empty; detect a real selection (for example a cardinality of 1) before labelling it as one.
Details
Verified: the context data source queries tychon-pqc* with terms aggregations of size: 1 on observer.hostname, tychon.application.name, server.address, network.protocol, tychon.tls.preferred_protocol and tychon.tls.preferred_cipher. The selectionType formula is datum.app != '' ? 'APPLICATION CONTEXT' : (datum.host != '' ? 'HOST CONTEXT' : 'NO SELECTION') and selectionId falls through to 'Select a host/app in the graph' only when both are empty. Whenever any application record exists in the time range the top bucket is non-empty, so before the user has selected a node the panel shows an arbitrary application name, its most common destination, protocol and cipher as if they were the selection, and the event count / first-seen / last-seen values describe the whole dataset. The only way to reach the 'NO SELECTION' prompt is an empty result set.
Recommendation:
Add cardinality aggregations and treat the result as a selection only when exactly one distinct value remains, for example:
"aggs": {
"app_n": {"cardinality": {"field": "tychon.application.name"}},
"host_n": {"cardinality": {"field": "observer.hostname"}},
"app": {"terms": {"field": "tychon.application.name", "size": 1}},
"host": {"terms": {"field": "observer.hostname", "size": 1}}
}then:
{"type": "formula", "as": "selectionType", "expr": "datum.app_n.value === 1 ? 'APPLICATION CONTEXT' : (datum.host_n.value === 1 ? 'HOST CONTEXT' : 'NO SELECTION')"}and blank the detail rows when selectionType is 'NO SELECTION'.
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| @@ -0,0 +1,4 @@ | |||
| {"@timestamp":"2026-07-06T17:03:00.055778Z","event.category":"network","event.dataset":"tychon.inventory","event.kind":"event","event.type":"info","id":"invalid-typed-fields-test-record-1","observer.id":"00000000-0000-4000-8000-000000000002","observer.hostname":"test-host-01","observer.domain":"example.test","certificate.not_before":"not-a-date","certificate.not_after":"also-not-a-date","cipher.last_seen":"not-a-date-either","tychon.application.port":"not-a-port","tychon.application.port_quantum_grade.score":"not-a-score","tychon.index":"inventory","tychon.type":"inventory"} | |||
| {"@timestamp":"2026-07-06T17:03:01.055778Z","event.category":"process","event.dataset":"tychon.app_certificate","event.kind":"event","event.type":"info","id":"valid-certificate-test-record-1","host.ip":"192.0.2.10","observer.id":"00000000-0000-4000-8000-000000000002","certificate.issuer_common_name":"Example Test CA","certificate.subject_common_name":"app.example.test","certificate.not_before":"2025-01-01T00:00:00Z","certificate.not_after":"2030-01-01T00:00:00Z","certificate.signature_algorithm":"SHA256-RSA","tychon.index":"certificates","tychon.type":"certificate"} | |||
There was a problem hiding this comment.
Severity: 🔵 Low confidence: medium path: packages/tychon_quantum_command/data_stream/tychon_pqc/_dev/test/pipeline/test-invalid-typed-fields.log:2
No fixture drives the comma-delimited host.ip branches (split_host_ip and the dotted host.ip normalisation script); add one record with a comma-separated host.ip string so that path is pinned.
Details
Verified: the pipeline has three code paths for host.ip: split_host_ip (line 677-682, runs when host.ip is a String), the script_normalize_host_ip_from_literal_dotted_field_or_comma_ script (lines 723-759, handles a literal dotted host.ip key and comma-delimited strings), and the list handling in the ECS copy logic. The only handwritten inputs that set host.ip give a single IP string (this record, "host.ip":"192.0.2.10") or an already-formed list (test-related-ip.json). No input carries a comma-delimited value such as "host.ip":"192.0.2.10, 2001:db8::1", which is the shape the vendor uses for observer.ip_addresses in every family fixture, so the split-and-trim behaviour and its interaction with related.ip are never exercised. This is a coverage gap only; no incorrect behaviour was demonstrated. The same record can also carry the tls.previous_supported_* keys once their mappings are settled (see the fields finding).
Recommendation:
Append one small anonymised record to this fixture (or to test-branch-coverage.log) and regenerate with elastic-package test pipeline --data-streams tychon_pqc --generate:
{"@timestamp":"2026-07-06T17:03:04.055778Z","event.category":"network","event.dataset":"tychon.inventory","event.kind":"event","event.type":"info","id":"comma-host-ip-test-record-1","observer.id":"00000000-0000-4000-8000-000000000002","host.ip":"192.0.2.50, 2001:db8::50","tychon.index":"inventory","tychon.type":"inventory"}
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
| **Exported fields** | ||
|
|
||
| {{ fields "tychon_pqc" }} |
There was a problem hiding this comment.
Severity: 🔵 Low confidence: high path: packages/tychon_quantum_command/_dev/build/docs/README.md:192
The README template writes its own **Exported fields** heading directly above the {{ fields }} helper, which emits the same heading itself, so the generated docs/README.md shows the heading twice; drop the hand-written heading and keep only the helper.
Details
Verified: _dev/build/docs/README.md lines 190-192 contain a literal **Exported fields** heading, a blank line, and {{ fields "tychon_pqc" }}. The elastic-package fields helper renders its own **Exported fields** heading before the table, and the committed generated docs/README.md shows the heading on consecutive lines 191 and 193 before the field table. The **Example event** heading above {{ event }} is redundant in the same way (the helper emits "An example event for tychon_pqc looks as following:") but does not duplicate text, so it is left to author preference.
Recommendation:
Remove the hand-written heading and let the helper render it, then regenerate docs/README.md with elastic-package build.
| **Exported fields** | |
| {{ fields "tychon_pqc" }} | |
| {{ fields "tychon_pqc" }} |
🤖 AI-Generated Review | Vera Review Bot - v0.4.2 | 📚 Knowledge base: integration-skills
⚠️ Automated review — verify suggestions before applying.
|
Proposed commit message
Add the TYCHON Quantum Command integration package for Elastic Agent and Fleet
This change introduces the initial
0.1.0release of thetychon_quantum_commandintegration package aligned to the current TYCHON Quantum Command release.WHAT:
tychon_pqclogs data stream for TYCHON Quantum Command NDJSON/JSON output collected through thefilestreaminput.logs-tychon_quantum_command.tychon_pqc-*and publish analytical destination indices for TYCHON datasets including inventory, applications, certificates, ciphers, crypto libraries, keystores, VPN clients, IPsec tunnels, MACsec, installed apps, browser extensions, assets, archives, and system readiness.WHY:
2.0.4so the initial integration release matches the currently released TQC version.Checklist
changelog.ymlfile.Author's Checklist
elastic-package checkcompletes successfully.elastic-package buildproducestychon_quantum_command-0.1.0.zip.sample_event.jsonis a real event and not the default placeholder.logs-tychon_quantum_command.tychon_pqc-*.How to test this PR locally
elastic/integrations.packages/tychon_quantum_command.