Skip to content

Semperis Lightning 4.1.0: merge CCF into existing offer (Function App + CCF) - #2

Open
MitchellGulledge3 wants to merge 8 commits into
masterfrom
semperis-lightning-ccf-multi-account-reference
Open

Semperis Lightning 4.1.0: merge CCF into existing offer (Function App + CCF)#2
MitchellGulledge3 wants to merge 8 commits into
masterfrom
semperis-lightning-ccf-multi-account-reference

Conversation

@MitchellGulledge3

@MitchellGulledge3 MitchellGulledge3 commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Tested 4.1.0 package for Semperis Lightning.

What this is

Update to the existing Content Hub offer azure-sentinel-solution-semperislightning (Netskope/SailPoint pattern):

  • Azure Functions connector → *_CL
  • CCF connector → *V2_CL

Portal Connect succeeded in workspace centralus after treating the zone dropdown as an array (parameters('zone')[0]) and bumping the CCF content version to 4.1.0.

Copilot review on Azure#14949

Addressed here:

  • MULTI-ACCOUNT.md is shippable (no “Do not merge”)
  • ReleaseNotes.md table alignment
  • createUiDefinition.json workspace filter uses /resourceGroups/<name>/
  • testParameters.json “set up”

Reference tree: Solutions/SemperisLightningCCF

Partner PR to apply these onto: Azure#14949

MitchellGulledge3 and others added 2 commits August 10, 2026 11:36
Reference implementation for the Semperis CCF migration. Opened for
discussion only. Auth shape is unresolved pending Semperis confirmation.

Multi-account follows the shipped Auth0 / Citrix DaaS pattern: addOnAttributes
are merged into each polled event, declared in the DCR input stream, and
projected by transformKql so every row carries its source tenant.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0efd0d8a-38ae-499b-bef8-a0062c4819f3
Defect B (blocked all deployments, including greenfield):
'bool' is not a valid column type for DCR streamDeclarations or for
workspaces/tables. Portal rejected the DCR with InvalidStreamDeclaration.
Now 'boolean' in every artifact, including the deployed mainTemplate.

Defect A (blocked workspaces with a prior 3.1.0 deploy):
Log Analytics custom tables allow additive schema changes only. Dropping
ConnectorName failed against existing tables. ConnectorName is restored in
all 7 tables and populated via ConnectorName=tostring(SemperisInstanceName).

Root enabler: mainTemplate.json was hand-maintained, so it drifted from the
reviewed artifacts and was never covered by tests. It is now generated, and
tests scan it directly.

Suite: 14/14.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0efd0d8a-38ae-499b-bef8-a0062c4819f3
@MitchellGulledge3

Copy link
Copy Markdown
Owner Author

Two deployment blockers found in live testing, now fixed (854e727)

Both surfaced deploying into real Sentinel workspaces. They are independent.

Defect B — blocked every deployment, including greenfield

bool is not a valid column type. Portal rejected the DCR:

InvalidPayload: Data collection rule is invalid,
[{"code":"InvalidStreamDeclaration","message":"'Type' must have one of the
allowed values: string,int,long,real,boolean,datetime,dynamic."}]

LightningAttackPaths_CL.Blowout was bool. Now boolean everywhere.

The two vocabularies are not identical:

Resource Allowed
workspaces/tables string, int, long, real, boolean, datetime, dynamic, guid
DCR streamDeclarations string, int, long, real, boolean, datetime, dynamic (no guid)

bool is in neither.

Defect A — blocked workspaces with a prior 3.1.0 deploy

Log Analytics custom tables are additive only. You can add columns, never drop or retype them. Dropping ConnectorName failed against existing tables:

Invalid output table schema: The following columns which exist in the current
schema do not exist in the new schema or have different types

ConnectorName is restored in all 7 tables and populated via ConnectorName=tostring(SemperisInstanceName), so existing customer queries keep working.

Only conditional on a prior CCF deploy. The legacy Function App schema is fully additively compatible — 0 conflicts.

Root enabler

mainTemplate.json was hand-maintained. It is the artifact that actually deploys, but tests only validated the standalone files. So it drifted and shipped invalid while the suite passed.

It is now generated from the same constants, and tests scan it directly. Type validation also runs at generation time, so an invalid type fails the build rather than the deployment.

Suite: 8/14 → 14/14. Every new guard was mutation-tested.

Still open

Not yet validated against a live workspace. Both fixes are verified against the ARM/DCR schema contracts and the portal's own error text. The next redeploy is the real test.

Auth remains the blocking question for Semperis — unchanged.

…orName

DO NOT MERGE. Reference only.

Every custom table now ends in V2_CL (LightningTier0NodesV2_CL and the six
others), matching the shipped SailPoint convention (SailPointIDN_EventsV2_CL).
The legacy Solutions/SemperisLightning Function App solution keeps writing the
v1 tables, so the two solutions now share no schema and can run side by side in
one workspace with no interaction.

Renamed everywhere: table resources and filenames, DCR streamDeclarations keys,
dataFlows streams and outputStream, poller streamName and dataType, the
connector definition graph/sample/dataType queries, and mainTemplate.json.

ConnectorName is dropped as redundant with SemperisInstanceName. It existed only
to satisfy the Log Analytics additive-only constraint against tables a prior
3.1.0 deploy created; the V2 tables are new, so no such constraint applies.

Version 4.0.0 — renaming every table is a breaking change. ARM contentVersion
stays 1.0.0.0, matching every shipped solution, because ARM validates it against
a four-part pattern.

MULTI-ACCOUNT.md is restored (it was dropped by the previous commit) and updated
with the V2 mapping.

Auth is still unresolved and unchanged: the Semperis token endpoint takes a
single apiKey field while CCF JwtToken models a userName/password pair, so the
config still pads with an invented ccfCompatibility field. This needs live
verification against real Semperis credentials.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0efd0d8a-38ae-499b-bef8-a0062c4819f3
@MitchellGulledge3

Copy link
Copy Markdown
Owner Author

4.0.0 — all seven tables renamed to V2

Pushed as d077544dca.

What changed

Every custom table now ends in V2_CL:

Legacy (unchanged, still written by the Function App) This solution now writes
LightningTier0Nodes_CL LightningTier0NodesV2_CL
LightningAttackPaths_CL LightningAttackPathsV2_CL
LightningAttackPathLinks_CL LightningAttackPathLinksV2_CL
LightningTier0Attackers_CL LightningTier0AttackersV2_CL
LightningIndicatorExecutions_CL LightningIndicatorExecutionsV2_CL
LightningIOEsMetadata_CL LightningIOEsMetadataV2_CL
LightningIOEResults_CL LightningIOEResultsV2_CL

Form matches the shipped SailPoint convention (SailPointIDN_EventsV2_CL).

Why

Zero overlap with the legacy Solutions/SemperisLightning Function App solution, which keeps writing the v1 tables. The two connectors now share no schema, so they can run side by side in one workspace with no interaction — no additive-only conflicts, no column fights, no ambiguity about which connector produced a row.

Scope of the rename

Table resources and filenames, DCR streamDeclarations keys, dataFlows[].streams[] and outputStream, poller dcrConfig.streamName and dataType, the connector definition graphQueries / sampleQueries / dataTypes / lastDataReceivedQuery, mainTemplate.json, and the package zip. A test fails the build if any v1 name survives anywhere, including inside the zip.

ConnectorName dropped

It only existed to satisfy the Log Analytics additive-only rule against tables a prior 3.1.0 deploy had created, and it duplicated SemperisInstanceName. V2 tables are brand new, so there is no constraint and no legacy consumer. Use SemperisInstanceName. The schema baseline was re-based to the V2 schemas rather than deleted, so once 4.0.0 ships a later column drop or retype is still caught.

Version

4.0.0, not 3.2.0 — renaming every table breaks every existing query, workbook and rule. ARM contentVersion deliberately stays 1.0.0.0: ARM validates it against a four-part pattern and rejects a three-part semver.

Validation

pwsh .script/local-validation/build-and-validate.ps1 -SolutionName SemperisLightningCCF -SkipPackagingBUILD SUCCESSFUL, 11 passed / 0 failed / 6 skipped, ARM-TTK 48/48. Candidate suite 17/17. Skipped validators need .NET 3.1/8.0 and trufflehog, which are not installed locally.

⚠️ Still unresolved — auth

Unchanged and unverified. The Semperis token endpoint takes a single apiKey field. CCF JwtToken models a userName/password pair. The config still pads with an invented ccfCompatibility field. If Semperis rejects unknown JSON fields, token acquisition fails and no stream ingests. This needs live verification against real credentials — it is the first thing to check on deploy.

Still DO NOT MERGE — reference only.

…p rule

Three verified findings, none of which change the shipped config:

- Documented JwtToken limitations say it requires username/password token
  acquisition and does not support API-key token requests, so the invented
  ccfCompatibility field has no documented basis. APIKey with
  IsApiKeyInPostPayload and OAuth2 client credentials are the documented
  alternatives. Recorded as options to raise with Semperis, not applied.
- Poller resource names are unchanged from 3.1.1, so upgrading updates the six
  pollers in place and repoints them at the V2 tables. The v1 tables are left
  behind with their data.
- A DCR transform projecting a column the destination table does not declare is
  silently discarded, billed but not stored. This is why the transform/table
  coherence test exists.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0efd0d8a-38ae-499b-bef8-a0062c4819f3
@MitchellGulledge3

Copy link
Copy Markdown
Owner Author

Addendum — three verified findings (bf9af483c6)

Documented in MULTI-ACCOUNT.md. None of them change the shipped config.

1. Auth — the ccfCompatibility pad has no documented basis. Microsoft Learn states JwtToken requires username/password token acquisition and does not support API-key token requests. Two documented alternatives to raise with Semperis, deliberately not applied here:

  • APIKey auth with IsApiKeyInPostPayload, if the polling endpoints accept the key directly and no JWT exchange is needed.
  • OAuth2 client credentials, if the token service supports it.

Source: data-connector-connection-rules-reference#authentication-configuration

2. Upgrading over an existing 3.1.1 connection. Poller resource names are unchanged (SemperisLightning<Stream>-<uniqueString(connectionName, zone)>), so installing 4.0.0 updates the six existing pollers in place and repoints them at the V2 tables. The v1 tables are left behind with their data and are not deleted; the Function App keeps writing them. Expect v1 CCF ingestion to simply stop at the upgrade timestamp.

3. A transform projecting a column the table does not declare is silently discarded — accepted without error, billed, not stored. Not an ingestion failure. That silent-data-loss mode is why test_every_transform_output_column_exists_in_its_destination_table was added.

Source: data-collection-transformations-create

Correction to my earlier comment: I said ARM "rejects" a three-part contentVersion. More precisely — the ARM JSON schema pattern requires four parts and ARM-TTK enforces it, but Learn says "you can provide any value", so runtime rejection is unproven. 1.0.0.0 is kept regardless: it matches every shipped solution and passes ARM-TTK 48/48.

MitchellGulledge3 and others added 2 commits August 10, 2026 16:12
Ports the two live-deployment fixes validated against a real Sentinel workspace:

4.0.1 - quoted deferred workspace reference. Inside a [[ expression the portal
textually substitutes parameters('workspace'), so it must be quoted as shipped
connectors do; the unquoted form produced concat(westus2, ...) and failed with
'expected token LeftParenthesis'.

4.0.2 - zone is a single-select Dropdown (scalar) but was declared type: array
and indexed parameters('zone')[0], producing the portal error 'Cannot read
properties of undefined (reading map)'. zone is now securestring everywhere.

Both fixes also close repeated drift where Package/mainTemplate.json was
hand-maintained; the generator now owns poller name, addOnAttributes, auth,
request, response and connection parameter types.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 0efd0d8a-38ae-499b-bef8-a0062c4819f3
Ship Function App and CCF connectors in one solution (Netskope/SailPoint pattern), reuse offer azure-sentinel-solution-semperislightning, and keep the zone dropdown as an array read via [0]. Package 4.1.0.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c9e9ef59-ac68-42ed-9911-c166bcaddd0f
@MitchellGulledge3 MitchellGulledge3 changed the title DO NOT MERGE: Semperis Lightning CCF multi-account reference candidate DO NOT MERGE: Semperis Lightning CCF + Function App on existing offer (4.1.0) Aug 19, 2026
Portal was still serving the 4.0.2 CCF content item after the offer merge. Align dataConnectorCCPVersion with the solution version so Connect uses the array-typed zone parameter. Verified Connect in workspace centralus.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c9e9ef59-ac68-42ed-9911-c166bcaddd0f
@MitchellGulledge3

Copy link
Copy Markdown
Owner Author

Pushed 02dbfb9c6d after a successful portal Connect in workspace centralus.

  • Solution / CCF content version: 4.1.0
  • Existing offer: azure-sentinel-solution-semperislightning
  • Both connectors present: Function App + CCF
  • Zone dropdown treated as an array (parameters('zone')[0])

Reference tree: https://github.com/MitchellGulledge3/Azure-Sentinel/tree/semperis-lightning-ccf-multi-account-reference/Solutions/SemperisLightningCCF

Make MULTI-ACCOUNT.md shippable (drop Do not merge), match workspace filters to /resourceGroups/<name>/, fix set up wording, and keep ReleaseNotes aligned with the 4.1.0 Function App + CCF merge.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: c9e9ef59-ac68-42ed-9911-c166bcaddd0f
@MitchellGulledge3 MitchellGulledge3 changed the title DO NOT MERGE: Semperis Lightning CCF + Function App on existing offer (4.1.0) Semperis Lightning 4.1.0: merge CCF into existing offer (Function App + CCF) Aug 20, 2026
@MitchellGulledge3

Copy link
Copy Markdown
Owner Author

Addressed Copilot nits from Azure#14949 in 92ab765d1f. PR title no longer says DO NOT MERGE — this is the merge-ready 4.1.0 Function App + CCF package.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant