diff --git a/deploy/README.md b/deploy/README.md
index 6647d0c76..48b2f8ecd 100644
--- a/deploy/README.md
+++ b/deploy/README.md
@@ -23,13 +23,27 @@ This directory contains deterministic deployment bundles for the core Stella Ops
`python ./ops/devops/telemetry/smoke_otel_collector.py` to verify the OTLP endpoints.
5. Commit the change alongside any documentation updates (e.g. install guide cross-links).
-Maintaining the digest linkage keeps offline/air-gapped installs reproducible and avoids tag drift between environments.
-
-### Additional tooling
-
-- `deploy/tools/check-channel-alignment.py` – verifies that Helm/Compose profiles reference the exact images listed in a release manifest. Run it for each channel before promoting a release.
-- `ops/devops/telemetry/generate_dev_tls.sh` – produces local CA/server/client certificates for Compose-based collector testing.
-- `ops/devops/telemetry/smoke_otel_collector.py` – sends OTLP traffic and asserts the collector accepted traces, metrics, and logs.
+Maintaining the digest linkage keeps offline/air-gapped installs reproducible and avoids tag drift between environments.
+
+### Surface.Env rollout warnings
+
+- Compose (`deploy/compose/env/*.env.example`) and Helm (`deploy/helm/stellaops/values-*.yaml`) now seed `SCANNER_SURFACE_*` variables so the worker and web service resolve cache roots, Surface.FS endpoints, and secrets providers through `StellaOps.Scanner.Surface.Env`.
+- During rollout, watch for structured log messages (and readiness output) prefixed with `surface.env.`—for example, `surface.env.cache_root_missing`, `surface.env.endpoint_unreachable`, or `surface.env.secrets_provider_invalid`.
+- Treat these warnings as deployment blockers: update the endpoint/cache/secrets values or permissions before promoting the environment, otherwise workers will fail fast at startup.
+- Air-gapped bundles default the secrets provider to `file` with `/etc/stellaops/secrets`; connected clusters default to `kubernetes`. Adjust the provider/root pair if your secrets manager differs.
+
+### Mongo2Go OpenSSL prerequisites
+
+- Linux runners that execute Mongo2Go-backed suites (Excititor, Scheduler, Graph, etc.) must expose OpenSSL 1.1 (`libcrypto.so.1.1`, `libssl.so.1.1`). The canonical copies live under `tests/native/openssl-1.1/linux-x64`.
+- Export `LD_LIBRARY_PATH="$(git rev-parse --show-toplevel)/tests/native/openssl-1.1/linux-x64:${LD_LIBRARY_PATH:-}"` before invoking `dotnet test`. Example:\
+ `LD_LIBRARY_PATH="$(pwd)/tests/native/openssl-1.1/linux-x64" dotnet test src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/StellaOps.Excititor.WebService.Tests.csproj --nologo`.
+- CI agents or Dockerfiles that host these tests should either mount the directory into the container or copy the two `.so` files into a directory that is already on the runtime library path.
+
+### Additional tooling
+
+- `deploy/tools/check-channel-alignment.py` – verifies that Helm/Compose profiles reference the exact images listed in a release manifest. Run it for each channel before promoting a release.
+- `ops/devops/telemetry/generate_dev_tls.sh` – produces local CA/server/client certificates for Compose-based collector testing.
+- `ops/devops/telemetry/smoke_otel_collector.py` – sends OTLP traffic and asserts the collector accepted traces, metrics, and logs.
- `ops/devops/telemetry/package_offline_bundle.py` – packages telemetry assets (config/Helm/Compose) into a signed tarball for air-gapped installs.
- `docs/modules/devops/runbooks/deployment-upgrade.md` – end-to-end instructions for upgrade, rollback, and channel promotion workflows (Helm + Compose).
diff --git a/deploy/compose/env/airgap.env.example b/deploy/compose/env/airgap.env.example
index 73beab11b..2a3581a77 100644
--- a/deploy/compose/env/airgap.env.example
+++ b/deploy/compose/env/airgap.env.example
@@ -27,6 +27,10 @@ SCANNER_EVENTS_DSN=
SCANNER_EVENTS_STREAM=stella.events
SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
+SCANNER_SURFACE_FS_ENDPOINT=http://rustfs:8080/api/v1
+SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface
+SCANNER_SURFACE_SECRETS_PROVIDER=file
+SCANNER_SURFACE_SECRETS_ROOT=/etc/stellaops/secrets
SCHEDULER_QUEUE_KIND=Nats
SCHEDULER_QUEUE_NATS_URL=nats://nats:4222
SCHEDULER_STORAGE_DATABASE=stellaops_scheduler
diff --git a/deploy/compose/env/dev.env.example b/deploy/compose/env/dev.env.example
index ed81829cf..988070b18 100644
--- a/deploy/compose/env/dev.env.example
+++ b/deploy/compose/env/dev.env.example
@@ -26,6 +26,11 @@ SCANNER_EVENTS_DSN=
SCANNER_EVENTS_STREAM=stella.events
SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
+# Surface.Env defaults keep worker/web service aligned with local RustFS and inline secrets.
+SCANNER_SURFACE_FS_ENDPOINT=http://rustfs:8080/api/v1
+SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface
+SCANNER_SURFACE_SECRETS_PROVIDER=inline
+SCANNER_SURFACE_SECRETS_ROOT=
SCHEDULER_QUEUE_KIND=Nats
SCHEDULER_QUEUE_NATS_URL=nats://nats:4222
SCHEDULER_STORAGE_DATABASE=stellaops_scheduler
diff --git a/deploy/compose/env/mirror.env.example b/deploy/compose/env/mirror.env.example
index 13cea5afa..9ec687b09 100644
--- a/deploy/compose/env/mirror.env.example
+++ b/deploy/compose/env/mirror.env.example
@@ -6,10 +6,16 @@ MONGO_INITDB_ROOT_PASSWORD=mirror-password
MINIO_ROOT_USER=stellaops-mirror
MINIO_ROOT_PASSWORD=mirror-minio-secret
RUSTFS_HTTP_PORT=8080
-
-# Mirror HTTP listeners
-MIRROR_GATEWAY_HTTP_PORT=8080
-MIRROR_GATEWAY_HTTPS_PORT=9443
+
+# Scanner surface integration
+SCANNER_SURFACE_FS_ENDPOINT=http://rustfs:8080/api/v1
+SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface
+SCANNER_SURFACE_SECRETS_PROVIDER=file
+SCANNER_SURFACE_SECRETS_ROOT=/etc/stellaops/secrets
+
+# Mirror HTTP listeners
+MIRROR_GATEWAY_HTTP_PORT=8080
+MIRROR_GATEWAY_HTTPS_PORT=9443
# Concelier mirror configuration
CONCELIER_MIRROR_LATEST_SEGMENT=latest
diff --git a/deploy/compose/env/prod.env.example b/deploy/compose/env/prod.env.example
index 2f43d9c14..218178c0b 100644
--- a/deploy/compose/env/prod.env.example
+++ b/deploy/compose/env/prod.env.example
@@ -26,9 +26,13 @@ SCANNER_EVENTS_ENABLED=true
SCANNER_EVENTS_DRIVER=redis
# Leave SCANNER_EVENTS_DSN empty to inherit the Redis queue DSN when SCANNER_QUEUE_BROKER uses redis://.
SCANNER_EVENTS_DSN=
-SCANNER_EVENTS_STREAM=stella.events
-SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
+SCANNER_EVENTS_STREAM=stella.events
+SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
+SCANNER_SURFACE_FS_ENDPOINT=https://surfacefs.prod.stella-ops.org/api/v1
+SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface
+SCANNER_SURFACE_SECRETS_PROVIDER=kubernetes
+SCANNER_SURFACE_SECRETS_ROOT=stellaops/scanner
SCHEDULER_QUEUE_KIND=Nats
SCHEDULER_QUEUE_NATS_URL=nats://nats:4222
SCHEDULER_STORAGE_DATABASE=stellaops_scheduler
diff --git a/deploy/compose/env/stage.env.example b/deploy/compose/env/stage.env.example
index e7f652daa..b3c494bd8 100644
--- a/deploy/compose/env/stage.env.example
+++ b/deploy/compose/env/stage.env.example
@@ -26,6 +26,10 @@ SCANNER_EVENTS_DSN=
SCANNER_EVENTS_STREAM=stella.events
SCANNER_EVENTS_PUBLISH_TIMEOUT_SECONDS=5
SCANNER_EVENTS_MAX_STREAM_LENGTH=10000
+SCANNER_SURFACE_FS_ENDPOINT=http://rustfs:8080/api/v1
+SCANNER_SURFACE_CACHE_ROOT=/var/lib/stellaops/surface
+SCANNER_SURFACE_SECRETS_PROVIDER=kubernetes
+SCANNER_SURFACE_SECRETS_ROOT=stellaops/scanner
SCHEDULER_QUEUE_KIND=Nats
SCHEDULER_QUEUE_NATS_URL=nats://nats:4222
SCHEDULER_STORAGE_DATABASE=stellaops_scheduler
diff --git a/deploy/helm/stellaops/values-airgap.yaml b/deploy/helm/stellaops/values-airgap.yaml
index 0241ed8b8..8b223efde 100644
--- a/deploy/helm/stellaops/values-airgap.yaml
+++ b/deploy/helm/stellaops/values-airgap.yaml
@@ -1,102 +1,102 @@
-global:
- profile: airgap
- release:
- version: "2025.09.2-airgap"
- channel: airgap
- manifestSha256: "b787b833dddd73960c31338279daa0b0a0dce2ef32bd32ef1aaf953d66135f94"
- image:
- pullPolicy: IfNotPresent
- labels:
- stellaops.io/channel: airgap
-
-configMaps:
- notify-config:
- data:
- notify.yaml: |
- storage:
- driver: mongo
- connectionString: "mongodb://notify-mongo.prod.svc.cluster.local:27017"
- database: "stellaops_notify"
- commandTimeoutSeconds: 60
-
- authority:
- enabled: true
- issuer: "https://authority.stella-ops.org"
- metadataAddress: "https://authority.stella-ops.org/.well-known/openid-configuration"
- requireHttpsMetadata: true
- allowAnonymousFallback: false
- backchannelTimeoutSeconds: 30
- tokenClockSkewSeconds: 60
- audiences:
- - notify
- readScope: notify.read
- adminScope: notify.admin
-
- api:
- basePath: "/api/v1/notify"
- internalBasePath: "/internal/notify"
- tenantHeader: "X-StellaOps-Tenant"
-
- plugins:
- baseDirectory: "/var/opt/stellaops"
- directory: "plugins/notify"
- searchPatterns:
- - "StellaOps.Notify.Connectors.*.dll"
- orderedPlugins:
- - StellaOps.Notify.Connectors.Slack
- - StellaOps.Notify.Connectors.Teams
- - StellaOps.Notify.Connectors.Email
- - StellaOps.Notify.Connectors.Webhook
-
- telemetry:
- enableRequestLogging: true
- minimumLogLevel: Warning
-services:
- authority:
- image: registry.stella-ops.org/stellaops/authority@sha256:5551a3269b7008cd5aceecf45df018c67459ed519557ccbe48b093b926a39bcc
- service:
- port: 8440
- env:
- STELLAOPS_AUTHORITY__ISSUER: "https://stellaops-authority:8440"
- STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
- STELLAOPS_AUTHORITY__ALLOWANONYMOUSFALLBACK: "false"
- signer:
- image: registry.stella-ops.org/stellaops/signer@sha256:ddbbd664a42846cea6b40fca6465bc679b30f72851158f300d01a8571c5478fc
- service:
- port: 8441
- env:
- SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- SIGNER__POE__INTROSPECTURL: "file:///offline/poe/introspect.json"
- SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
- attestor:
- image: registry.stella-ops.org/stellaops/attestor@sha256:1ff0a3124d66d3a2702d8e421df40fbd98cc75cb605d95510598ebbae1433c50
- service:
- port: 8442
- env:
- ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
- ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
- concelier:
- image: registry.stella-ops.org/stellaops/concelier@sha256:29e2e1a0972707e092cbd3d370701341f9fec2aa9316fb5d8100480f2a1c76b5
- service:
- port: 8445
- env:
- CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
- CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
- CONCELIER__STORAGE__S3__ACCESSKEYID: "stellaops-airgap"
- CONCELIER__STORAGE__S3__SECRETACCESSKEY: "airgap-minio-secret"
- CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- CONCELIER__AUTHORITY__RESILIENCE__ALLOWOFFLINECACHEFALLBACK: "true"
- CONCELIER__AUTHORITY__RESILIENCE__OFFLINECACHETOLERANCE: "00:45:00"
- volumeMounts:
- - name: concelier-jobs
- mountPath: /var/lib/concelier/jobs
- volumeClaims:
- - name: concelier-jobs
- claimName: stellaops-concelier-jobs
+global:
+ profile: airgap
+ release:
+ version: "2025.09.2-airgap"
+ channel: airgap
+ manifestSha256: "b787b833dddd73960c31338279daa0b0a0dce2ef32bd32ef1aaf953d66135f94"
+ image:
+ pullPolicy: IfNotPresent
+ labels:
+ stellaops.io/channel: airgap
+
+configMaps:
+ notify-config:
+ data:
+ notify.yaml: |
+ storage:
+ driver: mongo
+ connectionString: "mongodb://notify-mongo.prod.svc.cluster.local:27017"
+ database: "stellaops_notify"
+ commandTimeoutSeconds: 60
+
+ authority:
+ enabled: true
+ issuer: "https://authority.stella-ops.org"
+ metadataAddress: "https://authority.stella-ops.org/.well-known/openid-configuration"
+ requireHttpsMetadata: true
+ allowAnonymousFallback: false
+ backchannelTimeoutSeconds: 30
+ tokenClockSkewSeconds: 60
+ audiences:
+ - notify
+ readScope: notify.read
+ adminScope: notify.admin
+
+ api:
+ basePath: "/api/v1/notify"
+ internalBasePath: "/internal/notify"
+ tenantHeader: "X-StellaOps-Tenant"
+
+ plugins:
+ baseDirectory: "/var/opt/stellaops"
+ directory: "plugins/notify"
+ searchPatterns:
+ - "StellaOps.Notify.Connectors.*.dll"
+ orderedPlugins:
+ - StellaOps.Notify.Connectors.Slack
+ - StellaOps.Notify.Connectors.Teams
+ - StellaOps.Notify.Connectors.Email
+ - StellaOps.Notify.Connectors.Webhook
+
+ telemetry:
+ enableRequestLogging: true
+ minimumLogLevel: Warning
+services:
+ authority:
+ image: registry.stella-ops.org/stellaops/authority@sha256:5551a3269b7008cd5aceecf45df018c67459ed519557ccbe48b093b926a39bcc
+ service:
+ port: 8440
+ env:
+ STELLAOPS_AUTHORITY__ISSUER: "https://stellaops-authority:8440"
+ STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
+ STELLAOPS_AUTHORITY__ALLOWANONYMOUSFALLBACK: "false"
+ signer:
+ image: registry.stella-ops.org/stellaops/signer@sha256:ddbbd664a42846cea6b40fca6465bc679b30f72851158f300d01a8571c5478fc
+ service:
+ port: 8441
+ env:
+ SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ SIGNER__POE__INTROSPECTURL: "file:///offline/poe/introspect.json"
+ SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
+ attestor:
+ image: registry.stella-ops.org/stellaops/attestor@sha256:1ff0a3124d66d3a2702d8e421df40fbd98cc75cb605d95510598ebbae1433c50
+ service:
+ port: 8442
+ env:
+ ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
+ ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
+ concelier:
+ image: registry.stella-ops.org/stellaops/concelier@sha256:29e2e1a0972707e092cbd3d370701341f9fec2aa9316fb5d8100480f2a1c76b5
+ service:
+ port: 8445
+ env:
+ CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
+ CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
+ CONCELIER__STORAGE__S3__ACCESSKEYID: "stellaops-airgap"
+ CONCELIER__STORAGE__S3__SECRETACCESSKEY: "airgap-minio-secret"
+ CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ CONCELIER__AUTHORITY__RESILIENCE__ALLOWOFFLINECACHEFALLBACK: "true"
+ CONCELIER__AUTHORITY__RESILIENCE__OFFLINECACHETOLERANCE: "00:45:00"
+ volumeMounts:
+ - name: concelier-jobs
+ mountPath: /var/lib/concelier/jobs
+ volumeClaims:
+ - name: concelier-jobs
+ claimName: stellaops-concelier-jobs
scanner-web:
- image: registry.stella-ops.org/stellaops/scanner-web@sha256:3df8ca21878126758203c1a0444e39fd97f77ddacf04a69685cda9f1e5e94718
- service:
- port: 8444
+ image: registry.stella-ops.org/stellaops/scanner-web@sha256:3df8ca21878126758203c1a0444e39fd97f77ddacf04a69685cda9f1e5e94718
+ service:
+ port: 8444
env:
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
@@ -110,8 +110,12 @@ services:
SCANNER__EVENTS__STREAM: "stella.events"
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "file"
+ SCANNER_SURFACE_SECRETS_ROOT: "/etc/stellaops/secrets"
scanner-worker:
- image: registry.stella-ops.org/stellaops/scanner-worker@sha256:eea5d6cfe7835950c5ec7a735a651f2f0d727d3e470cf9027a4a402ea89c4fb5
+ image: registry.stella-ops.org/stellaops/scanner-worker@sha256:eea5d6cfe7835950c5ec7a735a651f2f0d727d3e470cf9027a4a402ea89c4fb5
env:
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
@@ -125,62 +129,66 @@ services:
SCANNER__EVENTS__STREAM: "stella.events"
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
- notify-web:
- image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
- service:
- port: 8446
- env:
- DOTNET_ENVIRONMENT: Production
- configMounts:
- - name: notify-config
- mountPath: /app/etc/notify.yaml
- subPath: notify.yaml
- configMap: notify-config
- excititor:
- image: registry.stella-ops.org/stellaops/excititor@sha256:65c0ee13f773efe920d7181512349a09d363ab3f3e177d276136bd2742325a68
- env:
- EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
- EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
- web-ui:
- image: registry.stella-ops.org/stellaops/web-ui@sha256:bee9668011ff414572131dc777faab4da24473fe12c230893f161cabee092a1d
- service:
- port: 9443
- targetPort: 8443
- env:
- STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
- mongo:
- class: infrastructure
- image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
- service:
- port: 27017
- command:
- - mongod
- - --bind_ip_all
- env:
- MONGO_INITDB_ROOT_USERNAME: stellaops-airgap
- MONGO_INITDB_ROOT_PASSWORD: stellaops-airgap
- volumeMounts:
- - name: mongo-data
- mountPath: /data/db
- volumeClaims:
- - name: mongo-data
- claimName: stellaops-mongo-data
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "file"
+ SCANNER_SURFACE_SECRETS_ROOT: "/etc/stellaops/secrets"
+ notify-web:
+ image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
+ service:
+ port: 8446
+ env:
+ DOTNET_ENVIRONMENT: Production
+ configMounts:
+ - name: notify-config
+ mountPath: /app/etc/notify.yaml
+ subPath: notify.yaml
+ configMap: notify-config
+ excititor:
+ image: registry.stella-ops.org/stellaops/excititor@sha256:65c0ee13f773efe920d7181512349a09d363ab3f3e177d276136bd2742325a68
+ env:
+ EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
+ EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-airgap:stellaops-airgap@stellaops-mongo:27017"
+ web-ui:
+ image: registry.stella-ops.org/stellaops/web-ui@sha256:bee9668011ff414572131dc777faab4da24473fe12c230893f161cabee092a1d
+ service:
+ port: 9443
+ targetPort: 8443
+ env:
+ STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
+ mongo:
+ class: infrastructure
+ image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
+ service:
+ port: 27017
+ command:
+ - mongod
+ - --bind_ip_all
+ env:
+ MONGO_INITDB_ROOT_USERNAME: stellaops-airgap
+ MONGO_INITDB_ROOT_PASSWORD: stellaops-airgap
+ volumeMounts:
+ - name: mongo-data
+ mountPath: /data/db
+ volumeClaims:
+ - name: mongo-data
+ claimName: stellaops-mongo-data
minio:
class: infrastructure
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
service:
port: 9000
- command:
- - server
- - /data
- - --console-address
- - :9001
- env:
- MINIO_ROOT_USER: stellaops-airgap
- MINIO_ROOT_PASSWORD: airgap-minio-secret
- volumeMounts:
- - name: minio-data
- mountPath: /data
+ command:
+ - server
+ - /data
+ - --console-address
+ - :9001
+ env:
+ MINIO_ROOT_USER: stellaops-airgap
+ MINIO_ROOT_PASSWORD: airgap-minio-secret
+ volumeMounts:
+ - name: minio-data
+ mountPath: /data
volumeClaims:
- name: minio-data
claimName: stellaops-minio-data
@@ -204,18 +212,18 @@ services:
volumeClaims:
- name: rustfs-data
claimName: stellaops-rustfs-data
- nats:
- class: infrastructure
- image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
- service:
- port: 4222
- command:
- - -js
- - -sd
- - /data
- volumeMounts:
- - name: nats-data
- mountPath: /data
- volumeClaims:
- - name: nats-data
- claimName: stellaops-nats-data
+ nats:
+ class: infrastructure
+ image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
+ service:
+ port: 4222
+ command:
+ - -js
+ - -sd
+ - /data
+ volumeMounts:
+ - name: nats-data
+ mountPath: /data
+ volumeClaims:
+ - name: nats-data
+ claimName: stellaops-nats-data
diff --git a/deploy/helm/stellaops/values-dev.yaml b/deploy/helm/stellaops/values-dev.yaml
index eb99fc833..bcd64aa0d 100644
--- a/deploy/helm/stellaops/values-dev.yaml
+++ b/deploy/helm/stellaops/values-dev.yaml
@@ -17,92 +17,92 @@ telemetry:
secretName: stellaops-otel-tls
configMaps:
- notify-config:
- data:
- notify.yaml: |
- storage:
- driver: mongo
- connectionString: "mongodb://notify-mongo.dev.svc.cluster.local:27017"
- database: "stellaops_notify_dev"
- commandTimeoutSeconds: 30
-
- authority:
- enabled: true
- issuer: "https://authority.dev.stella-ops.local"
- metadataAddress: "https://authority.dev.stella-ops.local/.well-known/openid-configuration"
- requireHttpsMetadata: false
- allowAnonymousFallback: false
- backchannelTimeoutSeconds: 30
- tokenClockSkewSeconds: 60
- audiences:
- - notify.dev
- readScope: notify.read
- adminScope: notify.admin
-
- api:
- basePath: "/api/v1/notify"
- internalBasePath: "/internal/notify"
- tenantHeader: "X-StellaOps-Tenant"
-
- plugins:
- baseDirectory: "../"
- directory: "plugins/notify"
- searchPatterns:
- - "StellaOps.Notify.Connectors.*.dll"
- orderedPlugins:
- - StellaOps.Notify.Connectors.Slack
- - StellaOps.Notify.Connectors.Teams
- - StellaOps.Notify.Connectors.Email
- - StellaOps.Notify.Connectors.Webhook
-
- telemetry:
- enableRequestLogging: true
- minimumLogLevel: Debug
+ notify-config:
+ data:
+ notify.yaml: |
+ storage:
+ driver: mongo
+ connectionString: "mongodb://notify-mongo.dev.svc.cluster.local:27017"
+ database: "stellaops_notify_dev"
+ commandTimeoutSeconds: 30
+
+ authority:
+ enabled: true
+ issuer: "https://authority.dev.stella-ops.local"
+ metadataAddress: "https://authority.dev.stella-ops.local/.well-known/openid-configuration"
+ requireHttpsMetadata: false
+ allowAnonymousFallback: false
+ backchannelTimeoutSeconds: 30
+ tokenClockSkewSeconds: 60
+ audiences:
+ - notify.dev
+ readScope: notify.read
+ adminScope: notify.admin
+
+ api:
+ basePath: "/api/v1/notify"
+ internalBasePath: "/internal/notify"
+ tenantHeader: "X-StellaOps-Tenant"
+
+ plugins:
+ baseDirectory: "../"
+ directory: "plugins/notify"
+ searchPatterns:
+ - "StellaOps.Notify.Connectors.*.dll"
+ orderedPlugins:
+ - StellaOps.Notify.Connectors.Slack
+ - StellaOps.Notify.Connectors.Teams
+ - StellaOps.Notify.Connectors.Email
+ - StellaOps.Notify.Connectors.Webhook
+
+ telemetry:
+ enableRequestLogging: true
+ minimumLogLevel: Debug
services:
- authority:
- image: registry.stella-ops.org/stellaops/authority@sha256:a8e8faec44a579aa5714e58be835f25575710430b1ad2ccd1282a018cd9ffcdd
- service:
- port: 8440
- env:
- STELLAOPS_AUTHORITY__ISSUER: "https://stellaops-authority:8440"
- STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
- STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
- STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
- signer:
- image: registry.stella-ops.org/stellaops/signer@sha256:8bfef9a75783883d49fc18e3566553934e970b00ee090abee9cb110d2d5c3298
- service:
- port: 8441
- env:
- SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- SIGNER__POE__INTROSPECTURL: "https://licensing.svc.local/introspect"
- SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
- attestor:
- image: registry.stella-ops.org/stellaops/attestor@sha256:5cc417948c029da01dccf36e4645d961a3f6d8de7e62fe98d845f07cd2282114
- service:
- port: 8442
- env:
- ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
- ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
- concelier:
- image: registry.stella-ops.org/stellaops/concelier@sha256:dafef3954eb4b837e2c424dd2d23e1e4d60fa83794840fac9cd3dea1d43bd085
- service:
- port: 8445
- env:
- CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
- CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
- CONCELIER__STORAGE__S3__ACCESSKEYID: "stellaops"
- CONCELIER__STORAGE__S3__SECRETACCESSKEY: "dev-minio-secret"
- CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- volumeMounts:
- - name: concelier-jobs
- mountPath: /var/lib/concelier/jobs
- volumes:
- - name: concelier-jobs
- emptyDir: {}
+ authority:
+ image: registry.stella-ops.org/stellaops/authority@sha256:a8e8faec44a579aa5714e58be835f25575710430b1ad2ccd1282a018cd9ffcdd
+ service:
+ port: 8440
+ env:
+ STELLAOPS_AUTHORITY__ISSUER: "https://stellaops-authority:8440"
+ STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
+ STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
+ STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
+ signer:
+ image: registry.stella-ops.org/stellaops/signer@sha256:8bfef9a75783883d49fc18e3566553934e970b00ee090abee9cb110d2d5c3298
+ service:
+ port: 8441
+ env:
+ SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ SIGNER__POE__INTROSPECTURL: "https://licensing.svc.local/introspect"
+ SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
+ attestor:
+ image: registry.stella-ops.org/stellaops/attestor@sha256:5cc417948c029da01dccf36e4645d961a3f6d8de7e62fe98d845f07cd2282114
+ service:
+ port: 8442
+ env:
+ ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
+ ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
+ concelier:
+ image: registry.stella-ops.org/stellaops/concelier@sha256:dafef3954eb4b837e2c424dd2d23e1e4d60fa83794840fac9cd3dea1d43bd085
+ service:
+ port: 8445
+ env:
+ CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
+ CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
+ CONCELIER__STORAGE__S3__ACCESSKEYID: "stellaops"
+ CONCELIER__STORAGE__S3__SECRETACCESSKEY: "dev-minio-secret"
+ CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ volumeMounts:
+ - name: concelier-jobs
+ mountPath: /var/lib/concelier/jobs
+ volumes:
+ - name: concelier-jobs
+ emptyDir: {}
scanner-web:
- image: registry.stella-ops.org/stellaops/scanner-web@sha256:e0dfdb087e330585a5953029fb4757f5abdf7610820a085bd61b457dbead9a11
- service:
- port: 8444
+ image: registry.stella-ops.org/stellaops/scanner-web@sha256:e0dfdb087e330585a5953029fb4757f5abdf7610820a085bd61b457dbead9a11
+ service:
+ port: 8444
env:
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
@@ -116,8 +116,12 @@ services:
SCANNER__EVENTS__STREAM: "stella.events"
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "inline"
+ SCANNER_SURFACE_SECRETS_ROOT: ""
scanner-worker:
- image: registry.stella-ops.org/stellaops/scanner-worker@sha256:92dda42f6f64b2d9522104a5c9ffb61d37b34dd193132b68457a259748008f37
+ image: registry.stella-ops.org/stellaops/scanner-worker@sha256:92dda42f6f64b2d9522104a5c9ffb61d37b34dd193132b68457a259748008f37
env:
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
@@ -131,61 +135,65 @@ services:
SCANNER__EVENTS__STREAM: "stella.events"
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
- notify-web:
- image: registry.stella-ops.org/stellaops/notify-web:2025.10.0-edge
- service:
- port: 8446
- env:
- DOTNET_ENVIRONMENT: Development
- configMounts:
- - name: notify-config
- mountPath: /app/etc/notify.yaml
- subPath: notify.yaml
- configMap: notify-config
- excititor:
- image: registry.stella-ops.org/stellaops/excititor@sha256:d9bd5cadf1eab427447ce3df7302c30ded837239771cc6433b9befb895054285
- env:
- EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
- EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
- web-ui:
- image: registry.stella-ops.org/stellaops/web-ui@sha256:38b225fa7767a5b94ebae4dae8696044126aac429415e93de514d5dd95748dcf
- service:
- port: 8443
- env:
- STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
- mongo:
- class: infrastructure
- image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
- service:
- port: 27017
- command:
- - mongod
- - --bind_ip_all
- env:
- MONGO_INITDB_ROOT_USERNAME: stellaops
- MONGO_INITDB_ROOT_PASSWORD: stellaops
- volumeMounts:
- - name: mongo-data
- mountPath: /data/db
- volumes:
- - name: mongo-data
- emptyDir: {}
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "inline"
+ SCANNER_SURFACE_SECRETS_ROOT: ""
+ notify-web:
+ image: registry.stella-ops.org/stellaops/notify-web:2025.10.0-edge
+ service:
+ port: 8446
+ env:
+ DOTNET_ENVIRONMENT: Development
+ configMounts:
+ - name: notify-config
+ mountPath: /app/etc/notify.yaml
+ subPath: notify.yaml
+ configMap: notify-config
+ excititor:
+ image: registry.stella-ops.org/stellaops/excititor@sha256:d9bd5cadf1eab427447ce3df7302c30ded837239771cc6433b9befb895054285
+ env:
+ EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
+ EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops:stellaops@stellaops-mongo:27017"
+ web-ui:
+ image: registry.stella-ops.org/stellaops/web-ui@sha256:38b225fa7767a5b94ebae4dae8696044126aac429415e93de514d5dd95748dcf
+ service:
+ port: 8443
+ env:
+ STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
+ mongo:
+ class: infrastructure
+ image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
+ service:
+ port: 27017
+ command:
+ - mongod
+ - --bind_ip_all
+ env:
+ MONGO_INITDB_ROOT_USERNAME: stellaops
+ MONGO_INITDB_ROOT_PASSWORD: stellaops
+ volumeMounts:
+ - name: mongo-data
+ mountPath: /data/db
+ volumes:
+ - name: mongo-data
+ emptyDir: {}
minio:
class: infrastructure
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
- service:
- port: 9000
- command:
- - server
- - /data
- - --console-address
- - :9001
- env:
- MINIO_ROOT_USER: stellaops
- MINIO_ROOT_PASSWORD: dev-minio-secret
- volumeMounts:
- - name: minio-data
- mountPath: /data
+ service:
+ port: 9000
+ command:
+ - server
+ - /data
+ - --console-address
+ - :9001
+ env:
+ MINIO_ROOT_USER: stellaops
+ MINIO_ROOT_PASSWORD: dev-minio-secret
+ volumeMounts:
+ - name: minio-data
+ mountPath: /data
volumes:
- name: minio-data
emptyDir: {}
@@ -203,18 +211,18 @@ services:
volumes:
- name: rustfs-data
emptyDir: {}
- nats:
- class: infrastructure
- image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
- service:
- port: 4222
- command:
- - -js
- - -sd
- - /data
- volumeMounts:
- - name: nats-data
- mountPath: /data
- volumes:
- - name: nats-data
- emptyDir: {}
+ nats:
+ class: infrastructure
+ image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
+ service:
+ port: 4222
+ command:
+ - -js
+ - -sd
+ - /data
+ volumeMounts:
+ - name: nats-data
+ mountPath: /data
+ volumes:
+ - name: nats-data
+ emptyDir: {}
diff --git a/deploy/helm/stellaops/values-prod.yaml b/deploy/helm/stellaops/values-prod.yaml
index bb1f57687..5426b76a0 100644
--- a/deploy/helm/stellaops/values-prod.yaml
+++ b/deploy/helm/stellaops/values-prod.yaml
@@ -1,221 +1,229 @@
-global:
- profile: prod
- release:
- version: "2025.09.2"
- channel: stable
- manifestSha256: "dc3c8fe1ab83941c838ccc5a8a5862f7ddfa38c2078e580b5649db26554565b7"
- image:
- pullPolicy: IfNotPresent
- labels:
- stellaops.io/channel: stable
- stellaops.io/profile: prod
-
-configMaps:
- notify-config:
- data:
- notify.yaml: |
- storage:
- driver: mongo
- connectionString: "mongodb://stellaops-mongo:27017"
- database: "stellaops_notify_prod"
- commandTimeoutSeconds: 45
-
- authority:
- enabled: true
- issuer: "https://authority.prod.stella-ops.org"
- metadataAddress: "https://authority.prod.stella-ops.org/.well-known/openid-configuration"
- requireHttpsMetadata: true
- allowAnonymousFallback: false
- backchannelTimeoutSeconds: 30
- tokenClockSkewSeconds: 60
- audiences:
- - notify
- readScope: notify.read
- adminScope: notify.admin
-
- api:
- basePath: "/api/v1/notify"
- internalBasePath: "/internal/notify"
- tenantHeader: "X-StellaOps-Tenant"
-
- plugins:
- baseDirectory: "/opt/stellaops"
- directory: "plugins/notify"
- searchPatterns:
- - "StellaOps.Notify.Connectors.*.dll"
- orderedPlugins:
- - StellaOps.Notify.Connectors.Slack
- - StellaOps.Notify.Connectors.Teams
- - StellaOps.Notify.Connectors.Email
- - StellaOps.Notify.Connectors.Webhook
-
- telemetry:
- enableRequestLogging: true
- minimumLogLevel: Information
-services:
- authority:
- image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
- service:
- port: 8440
- env:
- STELLAOPS_AUTHORITY__ISSUER: "https://authority.prod.stella-ops.org"
- STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
- STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- signer:
- image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
- service:
- port: 8441
- env:
- SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- SIGNER__POE__INTROSPECTURL: "https://licensing.prod.stella-ops.org/introspect"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- attestor:
- image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
- service:
- port: 8442
- env:
- ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- concelier:
- image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
- service:
- port: 8445
- env:
- CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
- CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- volumeMounts:
- - name: concelier-jobs
- mountPath: /var/lib/concelier/jobs
- volumeClaims:
- - name: concelier-jobs
- claimName: stellaops-concelier-jobs
- scanner-web:
- image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
- service:
- port: 8444
- env:
- SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
- SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
- SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
- SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
- SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
- SCANNER__EVENTS__ENABLED: "true"
- SCANNER__EVENTS__DRIVER: "redis"
- SCANNER__EVENTS__DSN: ""
- SCANNER__EVENTS__STREAM: "stella.events"
- SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
- SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- scanner-worker:
- image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
- replicas: 3
- env:
- SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
- SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
- SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
- SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
- SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
- SCANNER__EVENTS__ENABLED: "true"
- SCANNER__EVENTS__DRIVER: "redis"
- SCANNER__EVENTS__DSN: ""
- SCANNER__EVENTS__STREAM: "stella.events"
- SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
- SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- notify-web:
- image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
- service:
- port: 8446
- env:
- DOTNET_ENVIRONMENT: Production
- envFrom:
- - secretRef:
- name: stellaops-prod-notify
- configMounts:
- - name: notify-config
- mountPath: /app/etc/notify.yaml
- subPath: notify.yaml
- configMap: notify-config
- excititor:
- image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
- env:
- EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
- envFrom:
- - secretRef:
- name: stellaops-prod-core
- web-ui:
- image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
- service:
- port: 8443
- env:
- STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
- mongo:
- class: infrastructure
- image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
- service:
- port: 27017
- command:
- - mongod
- - --bind_ip_all
- envFrom:
- - secretRef:
- name: stellaops-prod-mongo
- volumeMounts:
- - name: mongo-data
- mountPath: /data/db
- volumeClaims:
- - name: mongo-data
- claimName: stellaops-mongo-data
- minio:
- class: infrastructure
- image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
- service:
- port: 9000
- command:
- - server
- - /data
- - --console-address
- - :9001
- envFrom:
- - secretRef:
- name: stellaops-prod-minio
- volumeMounts:
- - name: minio-data
- mountPath: /data
- volumeClaims:
- - name: minio-data
- claimName: stellaops-minio-data
- rustfs:
- class: infrastructure
- image: registry.stella-ops.org/stellaops/rustfs:2025.10.0-edge
- service:
- port: 8080
- command:
- - serve
- - --listen
- - 0.0.0.0:8080
- - --root
- - /data
- env:
- RUSTFS__LOG__LEVEL: info
- RUSTFS__STORAGE__PATH: /data
- volumeMounts:
- - name: rustfs-data
- mountPath: /data
- volumeClaims:
- - name: rustfs-data
- claimName: stellaops-rustfs-data
+global:
+ profile: prod
+ release:
+ version: "2025.09.2"
+ channel: stable
+ manifestSha256: "dc3c8fe1ab83941c838ccc5a8a5862f7ddfa38c2078e580b5649db26554565b7"
+ image:
+ pullPolicy: IfNotPresent
+ labels:
+ stellaops.io/channel: stable
+ stellaops.io/profile: prod
+
+configMaps:
+ notify-config:
+ data:
+ notify.yaml: |
+ storage:
+ driver: mongo
+ connectionString: "mongodb://stellaops-mongo:27017"
+ database: "stellaops_notify_prod"
+ commandTimeoutSeconds: 45
+
+ authority:
+ enabled: true
+ issuer: "https://authority.prod.stella-ops.org"
+ metadataAddress: "https://authority.prod.stella-ops.org/.well-known/openid-configuration"
+ requireHttpsMetadata: true
+ allowAnonymousFallback: false
+ backchannelTimeoutSeconds: 30
+ tokenClockSkewSeconds: 60
+ audiences:
+ - notify
+ readScope: notify.read
+ adminScope: notify.admin
+
+ api:
+ basePath: "/api/v1/notify"
+ internalBasePath: "/internal/notify"
+ tenantHeader: "X-StellaOps-Tenant"
+
+ plugins:
+ baseDirectory: "/opt/stellaops"
+ directory: "plugins/notify"
+ searchPatterns:
+ - "StellaOps.Notify.Connectors.*.dll"
+ orderedPlugins:
+ - StellaOps.Notify.Connectors.Slack
+ - StellaOps.Notify.Connectors.Teams
+ - StellaOps.Notify.Connectors.Email
+ - StellaOps.Notify.Connectors.Webhook
+
+ telemetry:
+ enableRequestLogging: true
+ minimumLogLevel: Information
+services:
+ authority:
+ image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
+ service:
+ port: 8440
+ env:
+ STELLAOPS_AUTHORITY__ISSUER: "https://authority.prod.stella-ops.org"
+ STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
+ STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ signer:
+ image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
+ service:
+ port: 8441
+ env:
+ SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ SIGNER__POE__INTROSPECTURL: "https://licensing.prod.stella-ops.org/introspect"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ attestor:
+ image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
+ service:
+ port: 8442
+ env:
+ ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ concelier:
+ image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
+ service:
+ port: 8445
+ env:
+ CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
+ CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ volumeMounts:
+ - name: concelier-jobs
+ mountPath: /var/lib/concelier/jobs
+ volumeClaims:
+ - name: concelier-jobs
+ claimName: stellaops-concelier-jobs
+ scanner-web:
+ image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
+ service:
+ port: 8444
+ env:
+ SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
+ SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
+ SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
+ SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
+ SCANNER__EVENTS__ENABLED: "true"
+ SCANNER__EVENTS__DRIVER: "redis"
+ SCANNER__EVENTS__DSN: ""
+ SCANNER__EVENTS__STREAM: "stella.events"
+ SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
+ SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "kubernetes"
+ SCANNER_SURFACE_SECRETS_ROOT: "stellaops/scanner"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ scanner-worker:
+ image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
+ replicas: 3
+ env:
+ SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
+ SCANNER__ARTIFACTSTORE__ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER__ARTIFACTSTORE__BUCKET: "scanner-artifacts"
+ SCANNER__ARTIFACTSTORE__TIMEOUTSECONDS: "30"
+ SCANNER__QUEUE__BROKER: "nats://stellaops-nats:4222"
+ SCANNER__EVENTS__ENABLED: "true"
+ SCANNER__EVENTS__DRIVER: "redis"
+ SCANNER__EVENTS__DSN: ""
+ SCANNER__EVENTS__STREAM: "stella.events"
+ SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
+ SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "kubernetes"
+ SCANNER_SURFACE_SECRETS_ROOT: "stellaops/scanner"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ notify-web:
+ image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
+ service:
+ port: 8446
+ env:
+ DOTNET_ENVIRONMENT: Production
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-notify
+ configMounts:
+ - name: notify-config
+ mountPath: /app/etc/notify.yaml
+ subPath: notify.yaml
+ configMap: notify-config
+ excititor:
+ image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
+ env:
+ EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-core
+ web-ui:
+ image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
+ service:
+ port: 8443
+ env:
+ STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
+ mongo:
+ class: infrastructure
+ image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
+ service:
+ port: 27017
+ command:
+ - mongod
+ - --bind_ip_all
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-mongo
+ volumeMounts:
+ - name: mongo-data
+ mountPath: /data/db
+ volumeClaims:
+ - name: mongo-data
+ claimName: stellaops-mongo-data
+ minio:
+ class: infrastructure
+ image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
+ service:
+ port: 9000
+ command:
+ - server
+ - /data
+ - --console-address
+ - :9001
+ envFrom:
+ - secretRef:
+ name: stellaops-prod-minio
+ volumeMounts:
+ - name: minio-data
+ mountPath: /data
+ volumeClaims:
+ - name: minio-data
+ claimName: stellaops-minio-data
+ rustfs:
+ class: infrastructure
+ image: registry.stella-ops.org/stellaops/rustfs:2025.10.0-edge
+ service:
+ port: 8080
+ command:
+ - serve
+ - --listen
+ - 0.0.0.0:8080
+ - --root
+ - /data
+ env:
+ RUSTFS__LOG__LEVEL: info
+ RUSTFS__STORAGE__PATH: /data
+ volumeMounts:
+ - name: rustfs-data
+ mountPath: /data
+ volumeClaims:
+ - name: rustfs-data
+ claimName: stellaops-rustfs-data
diff --git a/deploy/helm/stellaops/values-stage.yaml b/deploy/helm/stellaops/values-stage.yaml
index bc4dfe178..5d164cdb8 100644
--- a/deploy/helm/stellaops/values-stage.yaml
+++ b/deploy/helm/stellaops/values-stage.yaml
@@ -2,10 +2,10 @@ global:
profile: stage
release:
version: "2025.09.2"
- channel: stable
- manifestSha256: "dc3c8fe1ab83941c838ccc5a8a5862f7ddfa38c2078e580b5649db26554565b7"
- image:
- pullPolicy: IfNotPresent
+ channel: stable
+ manifestSha256: "dc3c8fe1ab83941c838ccc5a8a5862f7ddfa38c2078e580b5649db26554565b7"
+ image:
+ pullPolicy: IfNotPresent
labels:
stellaops.io/channel: stable
@@ -15,94 +15,94 @@ telemetry:
defaultTenant: stage
tls:
secretName: stellaops-otel-tls-stage
-
-configMaps:
- notify-config:
- data:
- notify.yaml: |
- storage:
- driver: mongo
- connectionString: "mongodb://notify-mongo.stage.svc.cluster.local:27017"
- database: "stellaops_notify_stage"
- commandTimeoutSeconds: 45
-
- authority:
- enabled: true
- issuer: "https://authority.stage.stella-ops.org"
- metadataAddress: "https://authority.stage.stella-ops.org/.well-known/openid-configuration"
- requireHttpsMetadata: true
- allowAnonymousFallback: false
- backchannelTimeoutSeconds: 30
- tokenClockSkewSeconds: 60
- audiences:
- - notify
- readScope: notify.read
- adminScope: notify.admin
-
- api:
- basePath: "/api/v1/notify"
- internalBasePath: "/internal/notify"
- tenantHeader: "X-StellaOps-Tenant"
-
- plugins:
- baseDirectory: "/opt/stellaops"
- directory: "plugins/notify"
- searchPatterns:
- - "StellaOps.Notify.Connectors.*.dll"
- orderedPlugins:
- - StellaOps.Notify.Connectors.Slack
- - StellaOps.Notify.Connectors.Teams
- - StellaOps.Notify.Connectors.Email
- - StellaOps.Notify.Connectors.Webhook
-
- telemetry:
- enableRequestLogging: true
- minimumLogLevel: Information
-services:
- authority:
- image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
- service:
- port: 8440
- env:
- STELLAOPS_AUTHORITY__ISSUER: "https://stellaops-authority:8440"
- STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
- STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
- STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
- signer:
- image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
- service:
- port: 8441
- env:
- SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- SIGNER__POE__INTROSPECTURL: "https://licensing.stage.stella-ops.internal/introspect"
- SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
- attestor:
- image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
- service:
- port: 8442
- env:
- ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
- ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
- concelier:
- image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
- service:
- port: 8445
- env:
- CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
- CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
- CONCELIER__STORAGE__S3__ACCESSKEYID: "stellaops-stage"
- CONCELIER__STORAGE__S3__SECRETACCESSKEY: "stage-minio-secret"
- CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
- volumeMounts:
- - name: concelier-jobs
- mountPath: /var/lib/concelier/jobs
- volumeClaims:
- - name: concelier-jobs
- claimName: stellaops-concelier-jobs
+
+configMaps:
+ notify-config:
+ data:
+ notify.yaml: |
+ storage:
+ driver: mongo
+ connectionString: "mongodb://notify-mongo.stage.svc.cluster.local:27017"
+ database: "stellaops_notify_stage"
+ commandTimeoutSeconds: 45
+
+ authority:
+ enabled: true
+ issuer: "https://authority.stage.stella-ops.org"
+ metadataAddress: "https://authority.stage.stella-ops.org/.well-known/openid-configuration"
+ requireHttpsMetadata: true
+ allowAnonymousFallback: false
+ backchannelTimeoutSeconds: 30
+ tokenClockSkewSeconds: 60
+ audiences:
+ - notify
+ readScope: notify.read
+ adminScope: notify.admin
+
+ api:
+ basePath: "/api/v1/notify"
+ internalBasePath: "/internal/notify"
+ tenantHeader: "X-StellaOps-Tenant"
+
+ plugins:
+ baseDirectory: "/opt/stellaops"
+ directory: "plugins/notify"
+ searchPatterns:
+ - "StellaOps.Notify.Connectors.*.dll"
+ orderedPlugins:
+ - StellaOps.Notify.Connectors.Slack
+ - StellaOps.Notify.Connectors.Teams
+ - StellaOps.Notify.Connectors.Email
+ - StellaOps.Notify.Connectors.Webhook
+
+ telemetry:
+ enableRequestLogging: true
+ minimumLogLevel: Information
+services:
+ authority:
+ image: registry.stella-ops.org/stellaops/authority@sha256:b0348bad1d0b401cc3c71cb40ba034c8043b6c8874546f90d4783c9dbfcc0bf5
+ service:
+ port: 8440
+ env:
+ STELLAOPS_AUTHORITY__ISSUER: "https://stellaops-authority:8440"
+ STELLAOPS_AUTHORITY__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
+ STELLAOPS_AUTHORITY__PLUGINDIRECTORIES__0: "/app/plugins"
+ STELLAOPS_AUTHORITY__PLUGINS__CONFIGURATIONDIRECTORY: "/app/etc/authority.plugins"
+ signer:
+ image: registry.stella-ops.org/stellaops/signer@sha256:8ad574e61f3a9e9bda8a58eb2700ae46813284e35a150b1137bc7c2b92ac0f2e
+ service:
+ port: 8441
+ env:
+ SIGNER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ SIGNER__POE__INTROSPECTURL: "https://licensing.stage.stella-ops.internal/introspect"
+ SIGNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
+ attestor:
+ image: registry.stella-ops.org/stellaops/attestor@sha256:0534985f978b0b5d220d73c96fddd962cd9135f616811cbe3bff4666c5af568f
+ service:
+ port: 8442
+ env:
+ ATTESTOR__SIGNER__BASEURL: "https://stellaops-signer:8441"
+ ATTESTOR__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
+ concelier:
+ image: registry.stella-ops.org/stellaops/concelier@sha256:c58cdcaee1d266d68d498e41110a589dd204b487d37381096bd61ab345a867c5
+ service:
+ port: 8445
+ env:
+ CONCELIER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
+ CONCELIER__STORAGE__S3__ENDPOINT: "http://stellaops-minio:9000"
+ CONCELIER__STORAGE__S3__ACCESSKEYID: "stellaops-stage"
+ CONCELIER__STORAGE__S3__SECRETACCESSKEY: "stage-minio-secret"
+ CONCELIER__AUTHORITY__BASEURL: "https://stellaops-authority:8440"
+ volumeMounts:
+ - name: concelier-jobs
+ mountPath: /var/lib/concelier/jobs
+ volumeClaims:
+ - name: concelier-jobs
+ claimName: stellaops-concelier-jobs
scanner-web:
- image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
- service:
- port: 8444
+ image: registry.stella-ops.org/stellaops/scanner-web@sha256:14b23448c3f9586a9156370b3e8c1991b61907efa666ca37dd3aaed1e79fe3b7
+ service:
+ port: 8444
env:
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
@@ -116,9 +116,13 @@ services:
SCANNER__EVENTS__STREAM: "stella.events"
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "kubernetes"
+ SCANNER_SURFACE_SECRETS_ROOT: "stellaops/scanner"
scanner-worker:
- image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
- replicas: 2
+ image: registry.stella-ops.org/stellaops/scanner-worker@sha256:32e25e76386eb9ea8bee0a1ad546775db9a2df989fab61ac877e351881960dab
+ replicas: 2
env:
SCANNER__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
SCANNER__ARTIFACTSTORE__DRIVER: "rustfs"
@@ -132,61 +136,65 @@ services:
SCANNER__EVENTS__STREAM: "stella.events"
SCANNER__EVENTS__PUBLISHTIMEOUTSECONDS: "5"
SCANNER__EVENTS__MAXSTREAMLENGTH: "10000"
- notify-web:
- image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
- service:
- port: 8446
- env:
- DOTNET_ENVIRONMENT: Production
- configMounts:
- - name: notify-config
- mountPath: /app/etc/notify.yaml
- subPath: notify.yaml
- configMap: notify-config
- excititor:
- image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
- env:
- EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
- EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
- web-ui:
- image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
- service:
- port: 8443
- env:
- STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
- mongo:
- class: infrastructure
- image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
- service:
- port: 27017
- command:
- - mongod
- - --bind_ip_all
- env:
- MONGO_INITDB_ROOT_USERNAME: stellaops-stage
- MONGO_INITDB_ROOT_PASSWORD: stellaops-stage
- volumeMounts:
- - name: mongo-data
- mountPath: /data/db
- volumeClaims:
- - name: mongo-data
- claimName: stellaops-mongo-data
+ SCANNER_SURFACE_FS_ENDPOINT: "http://stellaops-rustfs:8080/api/v1"
+ SCANNER_SURFACE_CACHE_ROOT: "/var/lib/stellaops/surface"
+ SCANNER_SURFACE_SECRETS_PROVIDER: "kubernetes"
+ SCANNER_SURFACE_SECRETS_ROOT: "stellaops/scanner"
+ notify-web:
+ image: registry.stella-ops.org/stellaops/notify-web:2025.09.2
+ service:
+ port: 8446
+ env:
+ DOTNET_ENVIRONMENT: Production
+ configMounts:
+ - name: notify-config
+ mountPath: /app/etc/notify.yaml
+ subPath: notify.yaml
+ configMap: notify-config
+ excititor:
+ image: registry.stella-ops.org/stellaops/excititor@sha256:59022e2016aebcef5c856d163ae705755d3f81949d41195256e935ef40a627fa
+ env:
+ EXCITITOR__CONCELIER__BASEURL: "https://stellaops-concelier:8445"
+ EXCITITOR__STORAGE__MONGO__CONNECTIONSTRING: "mongodb://stellaops-stage:stellaops-stage@stellaops-mongo:27017"
+ web-ui:
+ image: registry.stella-ops.org/stellaops/web-ui@sha256:10d924808c48e4353e3a241da62eb7aefe727a1d6dc830eb23a8e181013b3a23
+ service:
+ port: 8443
+ env:
+ STELLAOPS_UI__BACKEND__BASEURL: "https://stellaops-scanner-web:8444"
+ mongo:
+ class: infrastructure
+ image: docker.io/library/mongo@sha256:c258b26dbb7774f97f52aff52231ca5f228273a84329c5f5e451c3739457db49
+ service:
+ port: 27017
+ command:
+ - mongod
+ - --bind_ip_all
+ env:
+ MONGO_INITDB_ROOT_USERNAME: stellaops-stage
+ MONGO_INITDB_ROOT_PASSWORD: stellaops-stage
+ volumeMounts:
+ - name: mongo-data
+ mountPath: /data/db
+ volumeClaims:
+ - name: mongo-data
+ claimName: stellaops-mongo-data
minio:
class: infrastructure
image: docker.io/minio/minio@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e
service:
port: 9000
- command:
- - server
- - /data
- - --console-address
- - :9001
- env:
- MINIO_ROOT_USER: stellaops-stage
- MINIO_ROOT_PASSWORD: stage-minio-secret
- volumeMounts:
- - name: minio-data
- mountPath: /data
+ command:
+ - server
+ - /data
+ - --console-address
+ - :9001
+ env:
+ MINIO_ROOT_USER: stellaops-stage
+ MINIO_ROOT_PASSWORD: stage-minio-secret
+ volumeMounts:
+ - name: minio-data
+ mountPath: /data
volumeClaims:
- name: minio-data
claimName: stellaops-minio-data
@@ -210,18 +218,18 @@ services:
volumeClaims:
- name: rustfs-data
claimName: stellaops-rustfs-data
- nats:
- class: infrastructure
- image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
- service:
- port: 4222
- command:
- - -js
- - -sd
- - /data
- volumeMounts:
- - name: nats-data
- mountPath: /data
- volumeClaims:
- - name: nats-data
- claimName: stellaops-nats-data
+ nats:
+ class: infrastructure
+ image: docker.io/library/nats@sha256:c82559e4476289481a8a5196e675ebfe67eea81d95e5161e3e78eccfe766608e
+ service:
+ port: 4222
+ command:
+ - -js
+ - -sd
+ - /data
+ volumeMounts:
+ - name: nats-data
+ mountPath: /data
+ volumeClaims:
+ - name: nats-data
+ claimName: stellaops-nats-data
diff --git a/docs/dev/aoc-normalization-removal-notes.md b/docs/dev/aoc-normalization-removal-notes.md
index 40b2b7b9f..2e0c51c55 100644
--- a/docs/dev/aoc-normalization-removal-notes.md
+++ b/docs/dev/aoc-normalization-removal-notes.md
@@ -16,6 +16,9 @@ Document follow-up actions for CONCELIER-CORE-AOC-19-004 as we unwind the final
1. Introduce a raw linkset projection alongside the existing canonical mapper so Policy Engine can choose which flavour to consume. ✅ 2025-10-31: `AdvisoryObservation` now surfaces `RawLinkset`; Mongo documents store both canonical & raw shapes; tests/goldens updated.
2. Update observation factory/query tests to assert duplicate handling and ordering with the relaxed projection. ✅ 2025-10-31.
-3. Refresh docs (`docs/ingestion/aggregation-only-contract.md`) once behaviour lands to explain the “raw vs canonical linkset” split.
+3. Refresh docs (`docs/ingestion/aggregation-only-contract.md`) once behaviour lands to explain the “raw vs canonical linkset” split. ✅ 2025-11-06: Added invariant notes and rollout guidance, linked to `docs/migration/no-merge.md` and `docs/dev/raw-linkset-backfill-plan.md`.
4. Coordinate with Policy Guild to validate consumers against the new raw projection before flipping defaults. ↺ Ongoing — see action items in `docs/dev/raw-linkset-backfill-plan.md` (2025-10-31 handshake with POLICY-ENGINE-20-003 owners).
-
+
+- 2025-11-05: Catalogued residual normalization paths tied to the legacy Merge service and outlined `noMergeEnabled` feature-toggle work to keep AOC ingestion fully merge-free.
+- 2025-11-05 19:20Z: Observation factory/linkset now preserve upstream ordering and duplicates; canonicalisation shifts to downstream services.
+- 2025-11-06: Documented post-merge rollout plan and annotated sprint trackers with analyzer gating updates.
diff --git a/docs/dev/raw-linkset-backfill-plan.md b/docs/dev/raw-linkset-backfill-plan.md
index db6e0f2bf..a6a8d0a8b 100644
--- a/docs/dev/raw-linkset-backfill-plan.md
+++ b/docs/dev/raw-linkset-backfill-plan.md
@@ -1,6 +1,6 @@
# Raw Linkset Backfill & Adoption Plan
-_Last updated: 2025-10-31_
+_Last updated: 2025-11-06_
Owners: Concelier Storage Guild, DevOps Guild, Policy Guild
## Context
@@ -39,7 +39,7 @@ Owners: Concelier Storage Guild, DevOps Guild, Policy Guild
| 2025-10-31 | Handshake w/ Policy | Agreement to consume `rawLinkset`; this document created. |
| 2025-11-01 | Draft migration script | Validate against staging dataset snapshots. |
| 2025-11-04 | Storage task CONCELIER-STORE-AOC-19-005 due | Deliver script + runbook for review. |
-| 2025-11-06 | Staging backfill rehearsal | Target < 30 min runtime on 5M observations. |
+| 2025-11-06 | Staging backfill rehearsal | Target < 30 min runtime on 5M observations; docs refreshed to highlight raw vs canonical invariants and analyzer guardrails. |
| 2025-11-08 | Policy fixtures updated | POL engine branch consumes `rawLinkset`. |
| 2025-11-11 | Production rollout window | Pending DevOps sign-off after rehearsals. |
diff --git a/docs/implplan/SPRINT_110_ingestion_evidence.md b/docs/implplan/SPRINT_110_ingestion_evidence.md
index d3a54cf09..10c00d90d 100644
--- a/docs/implplan/SPRINT_110_ingestion_evidence.md
+++ b/docs/implplan/SPRINT_110_ingestion_evidence.md
@@ -91,7 +91,7 @@ CONCELIER-ATTEST-73-002 `Transparency metadata` | TODO | Ensure Conseiller expos
CONCELIER-CONSOLE-23-001 `Advisory aggregation views` | TODO | Expose `/console/advisories` endpoints returning aggregation groups (per linkset) with source chips, provider-reported severity columns (no local consensus), and provenance metadata for Console list + dashboard cards. Support filters by source, ecosystem, published/modified window, tenant enforcement. Dependencies: CONCELIER-LNM-21-201, CONCELIER-LNM-21-202. | Concelier WebService Guild, BE-Base Platform Guild (src/Concelier/StellaOps.Concelier.WebService/TASKS.md)
CONCELIER-CONSOLE-23-002 `Dashboard deltas API` | TODO | Provide aggregated advisory delta counts (new, modified, conflicting) for Console dashboard + live status ticker; emit structured events for queue lag metrics. Ensure deterministic counts across repeated queries. Dependencies: CONCELIER-CONSOLE-23-001, CONCELIER-LNM-21-203. | Concelier WebService Guild (src/Concelier/StellaOps.Concelier.WebService/TASKS.md)
CONCELIER-CONSOLE-23-003 `Search fan-out helpers` | TODO | Deliver fast lookup endpoints for CVE/GHSA/purl search (linksets, observations) returning evidence fragments for Console global search; implement caching + scope guards. Dependencies: CONCELIER-CONSOLE-23-001. | Concelier WebService Guild (src/Concelier/StellaOps.Concelier.WebService/TASKS.md)
-CONCELIER-CORE-AOC-19-004 `Remove ingestion normalization` | DOING (2025-10-28) | Strip normalization/dedup/severity logic from ingestion pipelines, delegate derived computations to Policy Engine, and update exporters/tests to consume raw documents only.
2025-10-29 19:05Z: Audit completed for `AdvisoryRawService`/Mongo repo to confirm alias order/dedup removal persists; identified remaining normalization in observation/linkset factory that will be revised to surface raw duplicates for Policy ingestion. Change sketch + regression matrix drafted under `docs/dev/aoc-normalization-removal-notes.md` (pending commit).
2025-10-31 20:45Z: Added raw linkset projection to observations/storage, exposing canonical+raw views, refreshed fixtures/tests, and documented behaviour in models/doc factory.
2025-10-31 21:10Z: Coordinated with Policy Engine (POLICY-ENGINE-20-003) on adoption timeline; backfill + consumer readiness tracked in `docs/dev/raw-linkset-backfill-plan.md`. Dependencies: CONCELIER-CORE-AOC-19-002, POLICY-AOC-19-003. | Concelier Core Guild (src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md)
+CONCELIER-CORE-AOC-19-004 `Remove ingestion normalization` | DOING (2025-10-28) | Strip normalization/dedup/severity logic from ingestion pipelines, delegate derived computations to Policy Engine, and update exporters/tests to consume raw documents only.
2025-10-29 19:05Z: Audit completed for `AdvisoryRawService`/Mongo repo to confirm alias order/dedup removal persists; identified remaining normalization in observation/linkset factory that will be revised to surface raw duplicates for Policy ingestion. Change sketch + regression matrix drafted under `docs/dev/aoc-normalization-removal-notes.md` (pending commit).
2025-10-31 20:45Z: Added raw linkset projection to observations/storage, exposing canonical+raw views, refreshed fixtures/tests, and documented behaviour in models/doc factory.
2025-10-31 21:10Z: Coordinated with Policy Engine (POLICY-ENGINE-20-003) on adoption timeline; backfill + consumer readiness tracked in `docs/dev/raw-linkset-backfill-plan.md`.
2025-11-05 14:20Z: Resumed work to map remaining normalization hooks tied to Merge service and capture requirements for the upcoming `noMergeEnabled` feature toggle.
2025-11-05 19:05Z: Hardened no-merge feature flag wiring by suppressing obsolete diagnostics and extending gating tests.
2025-11-06 16:10Z: Updated AOC references/backfill plan with raw-vs-canonical guidance and noted analyzer guardrails introduced under MERGE-LNM-21-002. Dependencies: CONCELIER-CORE-AOC-19-002, POLICY-AOC-19-003. | Concelier Core Guild (src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md)
CONCELIER-CORE-AOC-19-013 `Authority tenant scope smoke coverage` | TODO | Extend Concelier smoke/e2e fixtures to configure `requiredTenants` and assert cross-tenant rejection with updated Authority tokens. Dependencies: AUTH-AOC-19-002. | Concelier Core Guild (src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md)
@@ -210,7 +210,7 @@ Depends on: Sprint 110.B - Concelier.VI
Summary: Ingestion & Evidence focus on Concelier (phase VII).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-MERGE-LNM-21-002 | DOING (2025-11-03) | Refactor or retire `AdvisoryMergeService` and related pipelines, ensuring callers transition to observation/linkset APIs; add compile-time analyzer preventing merge service usage.
2025-11-03: Began dependency audit and call-site inventory ahead of deprecation plan; cataloging service registrations/tests referencing merge APIs. | BE-Merge (src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md)
+MERGE-LNM-21-002 | DOING (2025-11-03) | Refactor or retire `AdvisoryMergeService` and related pipelines, ensuring callers transition to observation/linkset APIs; add compile-time analyzer preventing merge service usage.
2025-11-03: Began dependency audit and call-site inventory ahead of deprecation plan; cataloging service registrations/tests referencing merge APIs.
2025-11-05 14:42Z: Drafting `concelier:features:noMergeEnabled` gating, merge job allowlist handling, and deprecation/telemetry changes prior to analyzer rollout.
2025-11-06 16:10Z: Landed analyzer project (`CONCELIER0002`), wired into Concelier WebService/tests, and updated docs to direct suppressions through explicit migration notes. | BE-Merge (src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md)
MERGE-LNM-21-003 Determinism/test updates | QA Guild, BE-Merge | Replace merge determinism suites with observation/linkset regression tests verifying no data mutation and conflicts remain visible. Dependencies: MERGE-LNM-21-002. | MERGE-LNM-21-002 (src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md)
@@ -227,7 +227,7 @@ EXCITITOR-AIRGAP-56-002 `Bundle provenance` | TODO | Persist bundle metadata on
EXCITITOR-AIRGAP-57-001 `Sealed-mode enforcement` | TODO | Block non-mirror connectors in sealed mode and surface remediation errors. Dependencies: EXCITITOR-AIRGAP-56-002. | Excititor Core Guild, AirGap Policy Guild (src/Excititor/__Libraries/StellaOps.Excititor.Core/TASKS.md)
EXCITITOR-AIRGAP-57-002 `Staleness annotations` | TODO | Annotate VEX statements with staleness metrics and expose via API. Dependencies: EXCITITOR-AIRGAP-57-001. | Excititor Core Guild, AirGap Time Guild (src/Excititor/__Libraries/StellaOps.Excititor.Core/TASKS.md)
EXCITITOR-AIRGAP-58-001 `Portable VEX evidence` | TODO | Package VEX evidence segments into portable evidence bundles linked to timeline. Dependencies: EXCITITOR-AIRGAP-57-002. | Excititor Core Guild, Evidence Locker Guild (src/Excititor/__Libraries/StellaOps.Excititor.Core/TASKS.md)
-EXCITITOR-ATTEST-01-003 – Verification suite & observability | Team Excititor Attestation | DOING (2025-10-22) – Continuing implementation: build `IVexAttestationVerifier`, wire metrics/logging, and add regression tests. Draft plan in `EXCITITOR-ATTEST-01-003-plan.md` (2025-10-19) guides scope; updating with worknotes as progress lands.
2025-10-31: Verifier now tolerates duplicate source providers from AOC raw projections, downgrades offline Rekor verification to a degraded result, and enforces trusted signer registry checks with detailed diagnostics/tests. | EXCITITOR-ATTEST-01-002 (src/Excititor/__Libraries/StellaOps.Excititor.Attestation/TASKS.md)
+EXCITITOR-ATTEST-01-003 – Verification suite & observability | Team Excititor Attestation | TODO (2025-11-06) – Continuing implementation: build `IVexAttestationVerifier`, wire metrics/logging, and add regression tests. Draft plan in `EXCITITOR-ATTEST-01-003-plan.md` (2025-10-19) guides scope; updating with worknotes as progress lands.
2025-10-31: Verifier now tolerates duplicate source providers from AOC raw projections, downgrades offline Rekor verification to a degraded result, and enforces trusted signer registry checks with detailed diagnostics/tests.
2025-11-05 14:35Z: Resuming with diagnostics/observability deliverables (typed diagnostics record, ActivitySource wiring, metrics dimensions) before WebService/Worker integration.
2025-11-06 07:12Z: Worker & web service suites pass with new diagnostics (`dotnet test` via staged libssl1.1); export envelope context exposed publicly for mirror bundle publishing.
2025-11-06 07:55Z: Paused—automation for OpenSSL shim tracked under `DEVOPS-OPENSSL-11-001/002`. | EXCITITOR-ATTEST-01-002 (src/Excititor/__Libraries/StellaOps.Excititor.Attestation/TASKS.md)
EXCITITOR-ATTEST-73-001 `VEX attestation payloads` | TODO | Provide VEX statement metadata (supplier identity, justification, scope) required for VEXAttestation payloads. Dependencies: EXCITITOR-ATTEST-01-003. | Excititor Core Guild, Attestation Payloads Guild (src/Excititor/__Libraries/StellaOps.Excititor.Core/TASKS.md)
EXCITITOR-ATTEST-73-002 `Chain provenance` | TODO | Expose linkage from VEX statements to subject/product for chain of custody graph. Dependencies: EXCITITOR-ATTEST-73-001. | Excititor Core Guild (src/Excititor/__Libraries/StellaOps.Excititor.Core/TASKS.md)
EXCITITOR-CONN-MS-01-003 – Trust metadata & provenance hints | Team Excititor Connectors – MSRC | TODO – Emit cosign/AAD issuer metadata, attach provenance details, and document policy integration. | EXCITITOR-CONN-MS-01-002, EXCITITOR-POLICY-01-001 (src/Excititor/__Libraries/StellaOps.Excititor.Connectors.MSRC.CSAF/TASKS.md)
diff --git a/docs/implplan/SPRINT_130_scanner_surface.md b/docs/implplan/SPRINT_130_scanner_surface.md
index 0f2276ec7..a7685198e 100644
--- a/docs/implplan/SPRINT_130_scanner_surface.md
+++ b/docs/implplan/SPRINT_130_scanner_surface.md
@@ -134,8 +134,8 @@ Summary: Scanner & Surface focus on Scanner (phase VII).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
SCANNER-ENTRYTRACE-18-504 | TODO | Emit EntryTrace AOC NDJSON (`entrytrace.entry/node/edge/target/warning/capability`) and wire CLI/service streaming outputs. Dependencies: SCANNER-ENTRYTRACE-18-503. | EntryTrace Guild (src/Scanner/__Libraries/StellaOps.Scanner.EntryTrace/TASKS.md)
-SCANNER-ENV-01 | DOING (2025-11-02) | Replace ad-hoc environment reads with `StellaOps.Scanner.Surface.Env` helpers for cache roots and CAS endpoints.
2025-11-02: Env helper wiring drafted for Worker startup; initial tests validate cache root resolution. | Scanner Worker Guild (src/Scanner/StellaOps.Scanner.Worker/TASKS.md)
-SCANNER-ENV-02 | DOING (2025-11-02) | Wire Surface.Env helpers into WebService hosting (cache roots, feature flags) and document configuration. Dependencies: SCANNER-ENV-01.
2025-11-02: WebService bootstrap now consumes Surface.Env helpers for cache roots and feature flag toggles; configuration doc draft pending. | Scanner WebService Guild, Ops Guild (src/Scanner/StellaOps.Scanner.WebService/TASKS.md)
+SCANNER-ENV-01 | TODO (2025-11-06) | Replace ad-hoc environment reads with `StellaOps.Scanner.Surface.Env` helpers for cache roots and CAS endpoints.
2025-11-02: Env helper wiring drafted for Worker startup; initial tests validate cache root resolution.
2025-11-05 14:55Z: Continuing integration by propagating resolved settings into cache/secret services and prepping worker smoke tests + docs updates.
2025-11-05 19:18Z: Bound `SurfaceCacheOptions` root to Surface.Env settings and added configurator unit coverage.
2025-11-06 17:05Z: Documented misconfiguration warnings and updated module README to highlight Surface.Env usage.
2025-11-06 07:45Z: Helm/Compose env profiles (dev/stage/prod/airgap/mirror) now emit `SCANNER_SURFACE_*` defaults and ops README covers rollout warnings.
2025-11-06 07:55Z: Paused pending automation tracked under `DEVOPS-OPENSSL-11-001/002` and additional Surface.Env fixtures. | Scanner Worker Guild (src/Scanner/StellaOps.Scanner.Worker/TASKS.md)
+SCANNER-ENV-02 | TODO (2025-11-06) | Wire Surface.Env helpers into WebService hosting (cache roots, feature flags) and document configuration. Dependencies: SCANNER-ENV-01.
2025-11-02: WebService bootstrap now consumes Surface.Env helpers for cache roots and feature flag toggles; configuration doc draft pending.
2025-11-05 14:55Z: Picking up configuration/documentation work and aligning API readiness checks with Surface.Env validation outputs.
2025-11-05 19:18Z: Added unit test for Surface.Env cache root binding and ensured configurator registration.
2025-11-06 17:05Z: Surface.Env design doc expanded with warning catalogue and release notes, README refreshed.
2025-11-06 07:45Z: Helm/Compose templates ship `SCANNER_SURFACE_*` defaults across dev/stage/prod/airgap/mirror profiles with rollout guidance in deploy docs.
2025-11-06 07:55Z: Paused; follow-up automation tracked under `DEVOPS-OPENSSL-11-001/002` and readiness tests outstanding. | Scanner WebService Guild, Ops Guild (src/Scanner/StellaOps.Scanner.WebService/TASKS.md)
SCANNER-ENV-03 | TODO | Adopt Surface.Env helpers for plugin configuration (cache roots, CAS endpoints, feature toggles). Dependencies: SCANNER-ENV-02. | BuildX Plugin Guild (src/Scanner/StellaOps.Scanner.Sbomer.BuildXPlugin/TASKS.md)
SCANNER-EVENTS-16-301 | BLOCKED (2025-10-26) | Emit orchestrator-compatible envelopes (`scanner.event.*`) and update integration tests to verify Notifier ingestion (no Redis queue coupling). | Scanner WebService Guild (src/Scanner/StellaOps.Scanner.WebService/TASKS.md)
SCANNER-EVENTS-16-302 | DOING (2025-10-26) | Extend orchestrator event links (report/policy/attestation) once endpoints are finalised across gateway + console. Dependencies: SCANNER-EVENTS-16-301. | Scanner WebService Guild (src/Scanner/StellaOps.Scanner.WebService/TASKS.md)
diff --git a/docs/implplan/SPRINT_150_scheduling_automation.md b/docs/implplan/SPRINT_150_scheduling_automation.md
index b15cee66f..92f55c8c6 100644
--- a/docs/implplan/SPRINT_150_scheduling_automation.md
+++ b/docs/implplan/SPRINT_150_scheduling_automation.md
@@ -81,11 +81,12 @@ Summary: Scheduling & Automation focus on Scheduler (phase I).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
SCHED-CONSOLE-23-001 | DONE (2025-11-03) | Extend runs APIs with live progress SSE endpoints (`/console/runs/{id}/stream`), queue lag summaries, diff metadata fetch, retry/cancel hooks with RBAC enforcement, and deterministic pagination for history views consumed by Console. | Scheduler WebService Guild, BE-Base Platform Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
-SCHED-CONSOLE-27-001 | DONE (2025-11-03) | Provide policy batch simulation orchestration endpoints (`/policies/simulations` POST/GET) exposing run creation, shard status, SSE progress, cancellation, and retries with RBAC enforcement. Dependencies: SCHED-CONSOLE-23-001. | Scheduler WebService Guild, Policy Registry Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
-SCHED-CONSOLE-27-002 | DONE (2025-11-05) | Emit telemetry endpoints/metrics (`policy_simulation_queue_depth`, `policy_simulation_latency_seconds`) and webhook callbacks for completion/failure consumed by Registry. Dependencies: SCHED-CONSOLE-27-001. | Scheduler WebService Guild, Observability Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
-> 2025-11-05: Resumed instrumentation work to match `policy_simulation_latency_seconds` naming, add coverage for SSE latency recording, and validate webhook sample alignment before closing.
-> 2025-11-05: Ship telemetry updates + tests; local `dotnet test` blocked by pre-existing GraphJobs accessibility errors (`IGraphJobStore.UpdateAsync`).
-SCHED-IMPACT-16-303 | TODO | Snapshot/compaction + invalidation for removed images; persistence to RocksDB/Redis per architecture. | Scheduler ImpactIndex Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/TASKS.md)
+SCHED-CONSOLE-27-001 | DONE (2025-11-03) | Provide policy batch simulation orchestration endpoints (`/policies/simulations` POST/GET) exposing run creation, shard status, SSE progress, cancellation, and retries with RBAC enforcement. Dependencies: SCHED-CONSOLE-23-001. | Scheduler WebService Guild, Policy Registry Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
+SCHED-CONSOLE-27-002 | DONE (2025-11-05) | Emit telemetry endpoints/metrics (`policy_simulation_queue_depth`, `policy_simulation_latency_seconds`) and webhook callbacks for completion/failure consumed by Registry. Dependencies: SCHED-CONSOLE-27-001. | Scheduler WebService Guild, Observability Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
+> 2025-11-05: Resumed instrumentation work to match `policy_simulation_latency_seconds` naming, add coverage for SSE latency recording, and validate webhook sample alignment before closing.
+> 2025-11-05: Ship telemetry updates + tests; local `dotnet test` blocked by pre-existing GraphJobs accessibility errors (`IGraphJobStore.UpdateAsync`).
+> 2025-11-06: Added tenant-aware tagging to `policy_simulation_queue_depth` gauge samples and extended metrics-provider unit coverage.
+SCHED-IMPACT-16-303 | TODO | Snapshot/compaction + invalidation for removed images; persistence to RocksDB/Redis per architecture. | Scheduler ImpactIndex Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/TASKS.md)
SCHED-SURFACE-01 | TODO | Evaluate Surface.FS pointers when planning delta scans to avoid redundant work and prioritise drift-triggered assets. | Scheduler Worker Guild (src/Scheduler/__Libraries/StellaOps.Scheduler.Worker/TASKS.md)
SCHED-VULN-29-001 | TODO | Expose resolver job APIs (`POST /vuln/resolver/jobs`, `GET /vuln/resolver/jobs/{id}`) to trigger candidate recomputation per artifact/policy change with RBAC and rate limits. | Scheduler WebService Guild, Findings Ledger Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
SCHED-VULN-29-002 | TODO | Provide projector lag metrics endpoint and webhook notifications for backlog breaches consumed by DevOps dashboards. Dependencies: SCHED-VULN-29-001. | Scheduler WebService Guild, Observability Guild (src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md)
diff --git a/docs/implplan/SPRINT_160_export_evidence.md b/docs/implplan/SPRINT_160_export_evidence.md
index 886a1f4e5..ab3b11a6e 100644
--- a/docs/implplan/SPRINT_160_export_evidence.md
+++ b/docs/implplan/SPRINT_160_export_evidence.md
@@ -19,7 +19,7 @@ Depends on: Sprint 110.A - AdvisoryAI, Sprint 120.A - AirGap, Sprint 130.A - Sca
Summary: Export & Evidence focus on ExportCenter (phase I).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-DVOFF-64-001 | DOING (2025-11-04) | Implement Export Center job `devportal --offline` bundling portal HTML, specs, SDK artifacts, changelogs, and verification manifest. | DevPortal Offline Guild, Exporter Guild (src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md)
+DVOFF-64-001 | DONE (2025-11-05) | Implement Export Center job `devportal --offline` bundling portal HTML, specs, SDK artifacts, changelogs, and verification manifest.
2025-11-05: Worker builds reproducible bundle, persists manifest/checksum/DSSE signature under `//`, and documents verification flow in `devportal-offline.md`. Unit coverage added for job + signer. | DevPortal Offline Guild, Exporter Guild (src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md)
DVOFF-64-002 | TODO | Provide verification CLI (`stella devportal verify bundle.tgz`) ensuring integrity before import. Dependencies: DVOFF-64-001. | DevPortal Offline Guild, AirGap Controller Guild (src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md)
EXPORT-AIRGAP-56-001 | TODO | Extend Export Center to build Mirror Bundles as export profiles, including advisories/VEX/policy packs manifesting DSSE/TUF metadata. | Exporter Service Guild, Mirror Creator Guild (src/ExportCenter/StellaOps.ExportCenter/TASKS.md)
EXPORT-AIRGAP-56-002 | TODO | Package Bootstrap Pack (images + charts) into OCI archives with signed manifests for air-gapped deployment. Dependencies: EXPORT-AIRGAP-56-001. | Exporter Service Guild, DevOps Guild (src/ExportCenter/StellaOps.ExportCenter/TASKS.md)
diff --git a/docs/implplan/SPRINT_180_experience_sdks.md b/docs/implplan/SPRINT_180_experience_sdks.md
index 00ca68b16..3bc0275bd 100644
--- a/docs/implplan/SPRINT_180_experience_sdks.md
+++ b/docs/implplan/SPRINT_180_experience_sdks.md
@@ -62,6 +62,7 @@ CLI-PARITY-41-002 | TODO | Implement `notify`, `aoc`, `auth` command groups, ide
CLI-POLICY-20-001 | TODO | Add `stella policy new | DevEx/CLI Guild (src/Cli/StellaOps.Cli/TASKS.md)
CLI-POLICY-23-004 | TODO | Add `stella policy lint` command validating SPL files with compiler diagnostics; support JSON output. Dependencies: CLI-POLICY-20-001. | DevEx/CLI Guild (src/Cli/StellaOps.Cli/TASKS.md)
CLI-POLICY-23-005 | DOING (2025-10-28) | Implement `stella policy activate` with scheduling window, approval enforcement, and summary output. Dependencies: CLI-POLICY-23-004. | DevEx/CLI Guild (src/Cli/StellaOps.Cli/TASKS.md)
+> 2025-11-06: CLI enforces `--version` as mandatory and adds scheduled activation timestamp normalization tests while keeping exit codes intact.
CLI-POLICY-23-006 | TODO | Provide `stella policy history` and `stella policy explain` commands to pull run history and explanation trees. Dependencies: CLI-POLICY-23-005. | DevEx/CLI Guild (src/Cli/StellaOps.Cli/TASKS.md)
CLI-POLICY-27-001 | TODO | Implement policy workspace commands (`stella policy init`, `edit`, `lint`, `compile`, `test`) with template selection, local cache, JSON output, and deterministic temp directories. Dependencies: CLI-POLICY-23-006. | DevEx/CLI Guild (src/Cli/StellaOps.Cli/TASKS.md)
diff --git a/docs/implplan/SPRINT_200_documentation_process.md b/docs/implplan/SPRINT_200_documentation_process.md
index a7af6405a..40108f45e 100644
--- a/docs/implplan/SPRINT_200_documentation_process.md
+++ b/docs/implplan/SPRINT_200_documentation_process.md
@@ -265,7 +265,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Attestor).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-ATTESTOR-DOCS-0001 | DOING (2025-10-29) | See ./AGENTS.md | Docs Guild (docs/modules/attestor/TASKS.md)
+ATTESTOR-DOCS-0001 | DONE (2025-11-05) | README updated with platform-events release (attestor.logged@1 canonical samples, schema validation notes). | Docs Guild (docs/modules/attestor/TASKS.md)
ATTESTOR-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/attestor/TASKS.md)
ATTESTOR-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/attestor/TASKS.md)
@@ -305,7 +305,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Concelier).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-CONCELIER-DOCS-0001 | DOING (2025-10-29) | See ./AGENTS.md | Docs Guild (docs/modules/concelier/TASKS.md)
+CONCELIER-DOCS-0001 | DONE (2025-11-05) | README updated to reference 2025-10-22 authority toggle rollout guidance (quickstart + authority audit runbook). | Docs Guild (docs/modules/concelier/TASKS.md)
CONCELIER-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/concelier/TASKS.md)
CONCELIER-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/concelier/TASKS.md)
@@ -325,7 +325,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Excititor).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-EXCITITOR-DOCS-0001 | TODO | See ./AGENTS.md | Docs Guild (docs/modules/excititor/TASKS.md)
+EXCITITOR-DOCS-0001 | DONE (2025-11-05) | README updated with consensus API beta note ([docs/updates/2025-11-05-excitor-consensus-beta.md](../updates/2025-11-05-excitor-consensus-beta.md)) and consensus JSON sample ([docs/vex/consensus-json.md](../vex/consensus-json.md)). | Docs Guild (docs/modules/excititor/TASKS.md)
EXCITITOR-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/excititor/TASKS.md)
EXCITITOR-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/excititor/TASKS.md)
@@ -335,7 +335,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Export Center).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-EXPORT CENTER-DOCS-0001 | DOING (2025-10-29) | See ./AGENTS.md | Docs Guild (docs/modules/export-center/TASKS.md)
+EXPORT CENTER-DOCS-0001 | DONE (2025-11-05) | README updated to cover devportal offline profile, DSSE manifest signature, and links to provenance docs per 2025-10-29 export-center release update. | Docs Guild (docs/modules/export-center/TASKS.md)
EXPORT CENTER-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/export-center/TASKS.md)
EXPORT CENTER-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/export-center/TASKS.md)
@@ -367,7 +367,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Orchestrator).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-SOURCE---JOB-ORCHESTRATOR-DOCS-0001 | DOING (2025-10-29) | Align with ./AGENTS.md | Docs Guild (docs/modules/orchestrator/TASKS.md)
+SOURCE---JOB-ORCHESTRATOR-DOCS-0001 | DONE (2025-11-05) | README reflects the 2025-11-01 Authority quota/backfill scope release and auditing requirements. | Docs Guild (docs/modules/orchestrator/TASKS.md)
SOURCE---JOB-ORCHESTRATOR-ENG-0001 | TODO | Sync into ../../TASKS.md | Module Team (docs/modules/orchestrator/TASKS.md)
SOURCE---JOB-ORCHESTRATOR-OPS-0001 | TODO | Document outputs in ./README.md | Ops Guild (docs/modules/orchestrator/TASKS.md)
@@ -407,7 +407,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Scanner).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-SCANNER-DOCS-0001 | DOING (2025-10-29) | See ./AGENTS.md | Docs Guild (docs/modules/scanner/TASKS.md)
+SCANNER-DOCS-0001 | DONE (2025-11-05) | README updated with the 2025-10-19 platform-events release (scanner.report.ready@1 / scan.completed@1 DSSE envelopes + samples). | Docs Guild (docs/modules/scanner/TASKS.md)
SCANNER-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/scanner/TASKS.md)
SCANNER-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/scanner/TASKS.md)
@@ -427,7 +427,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Signer).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-SIGNER-DOCS-0001 | DOING (2025-10-29) | See ./AGENTS.md | Docs Guild (docs/modules/signer/TASKS.md)
+SIGNER-DOCS-0001 | DONE (2025-11-05) | README updated with Sprint 11 signing-chain release details (sign/dsse, verify/referrers, quota enforcement). | Docs Guild (docs/modules/signer/TASKS.md)
SIGNER-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/signer/TASKS.md)
SIGNER-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/signer/TASKS.md)
@@ -437,7 +437,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Telemetry).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-TELEMETRY-DOCS-0001 | DOING (2025-10-29) | See ./AGENTS.md | Docs Guild (docs/modules/telemetry/TASKS.md)
+TELEMETRY-DOCS-0001 | DONE (2025-11-05) | README updated with Sprint 23 console security alert pack (console-security Grafana board + burn-rate alert). | Docs Guild (docs/modules/telemetry/TASKS.md)
TELEMETRY-ENG-0001 | TODO | Update status via ./AGENTS.md workflow | Module Team (docs/modules/telemetry/TASKS.md)
TELEMETRY-OPS-0001 | TODO | Sync outcomes back to ../../TASKS.md | Ops Guild (docs/modules/telemetry/TASKS.md)
@@ -478,7 +478,7 @@ Depends on: Sprint 100.A - Attestor, Sprint 110.A - AdvisoryAI, Sprint 120.A - A
Summary: Documentation & Process focus on Docs Modules Vuln Explorer).
Task ID | State | Task description | Owners (Source)
--- | --- | --- | ---
-VULNERABILITY-EXPLORER-DOCS-0001 | DOING (2025-10-29) | Align with ./AGENTS.md | Docs Guild (docs/modules/vuln-explorer/TASKS.md)
+VULNERABILITY-EXPLORER-DOCS-0001 | DONE (2025-11-05) | README updated with 2025-11-03 access-controls release (attachment signing tokens + Authority scope guidance). | Docs Guild (docs/modules/vuln-explorer/TASKS.md)
VULNERABILITY-EXPLORER-ENG-0001 | TODO | Sync into ../../TASKS.md | Module Team (docs/modules/vuln-explorer/TASKS.md)
VULNERABILITY-EXPLORER-OPS-0001 | TODO | Document outputs in ./README.md | Ops Guild (docs/modules/vuln-explorer/TASKS.md)
diff --git a/docs/ingestion/aggregation-only-contract.md b/docs/ingestion/aggregation-only-contract.md
index 78fcd6b87..7ec008c57 100644
--- a/docs/ingestion/aggregation-only-contract.md
+++ b/docs/ingestion/aggregation-only-contract.md
@@ -1,181 +1,181 @@
-# Aggregation-Only Contract Reference
-
-> The Aggregation-Only Contract (AOC) is the governing rule set that keeps StellaOps ingestion services deterministic, policy-neutral, and auditable. It applies to Concelier, Excititor, and any future collectors that write raw advisory or VEX documents.
-
-## 1. Purpose and Scope
-
-- Defines the canonical behaviour for `advisory_raw` and `vex_raw` collections and the linkset hints they may emit.
-- Applies to every ingestion runtime (`StellaOps.Concelier.*`, `StellaOps.Excititor.*`), the Authority scopes that guard them, and the DevOps/QA surfaces that verify compliance.
-- Complements the high-level architecture in [Concelier](../modules/concelier/architecture.md) and Authority enforcement documented in [Authority Architecture](../modules/authority/architecture.md).
+# Aggregation-Only Contract Reference
+
+> The Aggregation-Only Contract (AOC) is the governing rule set that keeps StellaOps ingestion services deterministic, policy-neutral, and auditable. It applies to Concelier, Excititor, and any future collectors that write raw advisory or VEX documents.
+
+## 1. Purpose and Scope
+
+- Defines the canonical behaviour for `advisory_raw` and `vex_raw` collections and the linkset hints they may emit.
+- Applies to every ingestion runtime (`StellaOps.Concelier.*`, `StellaOps.Excititor.*`), the Authority scopes that guard them, and the DevOps/QA surfaces that verify compliance.
+- Complements the high-level architecture in [Concelier](../modules/concelier/architecture.md) and Authority enforcement documented in [Authority Architecture](../modules/authority/architecture.md).
- Paired guidance: see the guard-rail checkpoints in [AOC Guardrails](../aoc/aoc-guardrails.md), the implementation reference in [AOC Guard Library](../aoc/guard-library.md), and CLI usage that will land in `/docs/modules/cli/guides/` as part of Sprint 19 follow-up.
-
-## 2. Philosophy and Goals
-
-- Preserve upstream truth: ingestion only captures immutable raw facts plus provenance, never derived severity or policy decisions.
-- Defer interpretation: Policy Engine and downstream overlays remain the sole writers of materialised findings, severity, consensus, or risk scores.
-- Make every write explainable: provenance, signatures, and content hashes are required so operators can prove where each fact originated.
-- Keep outputs reproducible: identical inputs must yield identical documents, hashes, and linksets across replays and air-gapped installs.
-
-## 3. Contract Invariants
-
-| # | Invariant | What it forbids or requires | Enforcement surfaces |
-|---|-----------|-----------------------------|----------------------|
-| 1 | No derived severity at ingest | Reject top-level keys such as `severity`, `cvss`, `effective_status`, `consensus_provider`, `risk_score`. Raw upstream CVSS remains inside `content.raw`. | Mongo schema validator, `AOCWriteGuard`, Roslyn analyzer, `stella aoc verify`. |
-| 2 | No merges or opinionated dedupe | Each upstream document persists on its own; ingestion never collapses multiple vendors into one document. | Repository interceptors, unit/fixture suites. |
-| 3 | Provenance is mandatory | `source.*`, `upstream.*`, and `signature` metadata must be present; missing provenance triggers `ERR_AOC_004`. | Schema validator, guard, CLI verifier. |
-| 4 | Idempotent upserts | Writes keyed by `(vendor, upstream_id, content_hash)` either no-op or insert a new revision with `supersedes`. Duplicate hashes map to the same document. | Repository guard, storage unique index, CI smoke tests. |
-| 5 | Append-only revisions | Updates create a new document with `supersedes` pointer; no in-place mutation of content. | Mongo schema (`supersedes` format), guard, data migration scripts. |
-| 6 | Linkset only | Ingestion may compute link hints (`purls`, `cpes`, IDs) to accelerate joins, but must not transform or infer severity or policy. Observations now persist both canonical linksets (for indexed queries) and raw linksets (preserving upstream order/duplicates) so downstream policy can decide how to normalise. | Linkset builders reviewed via fixtures/analyzers; raw-vs-canonical parity covered by observation fixtures. |
-| 7 | Policy-only effective findings | Only Policy Engine identities can write `effective_finding_*`; ingestion callers receive `ERR_AOC_006` if they attempt it. | Authority scopes, Policy Engine guard. |
-| 8 | Schema safety | Unknown top-level keys reject with `ERR_AOC_007`; timestamps use ISO 8601 UTC strings; tenant is required. | Mongo validator, JSON schema tests. |
-| 9 | Clock discipline | Collectors stamp `fetched_at` and `received_at` monotonically per batch to support reproducibility windows. | Collector contracts, QA fixtures. |
-
-## 4. Raw Schemas
-
-### 4.1 `advisory_raw`
-
-| Field | Type | Notes |
-|-------|------|-------|
-| `_id` | string | `advisory_raw:{source}:{upstream_id}:{revision}`; deterministic and tenant-scoped. |
-| `tenant` | string | Required; injected by Authority middleware and asserted by schema validator. |
-| `source.vendor` | string | Provider identifier (e.g., `redhat`, `osv`, `ghsa`). |
-| `source.stream` | string | Connector stream name (`csaf`, `osv`, etc.). |
-| `source.api` | string | Absolute URI of upstream document; stored for traceability. |
-| `source.collector_version` | string | Semantic version of the collector. |
-| `upstream.upstream_id` | string | Vendor- or ecosystem-provided identifier (CVE, GHSA, vendor ID). |
-| `upstream.document_version` | string | Upstream issued timestamp or revision string. |
-| `upstream.fetched_at` / `received_at` | string | ISO 8601 UTC timestamps recorded by the collector. |
-| `upstream.content_hash` | string | `sha256:` digest of the raw payload used for idempotency. |
-| `upstream.signature` | object | Required structure storing `present`, `format`, `key_id`, `sig`; even unsigned payloads set `present: false`. |
-| `content.format` | string | Source format (`CSAF`, `OSV`, etc.). |
-| `content.spec_version` | string | Upstream spec version when known. |
-| `content.raw` | object | Full upstream payload, untouched except for transport normalisation. |
-| `identifiers` | object | Upstream identifiers (`cve`, `ghsa`, `aliases`, etc.) captured as provided (trimmed, order preserved, duplicates allowed). |
-| `linkset` | object | Join hints (see section 4.3). |
-| `supersedes` | string or null | Points to previous revision of same upstream doc when content hash changes. |
-
-### 4.2 `vex_raw`
-
-| Field | Type | Notes |
-|-------|------|-------|
-| `_id` | string | `vex_raw:{source}:{upstream_id}:{revision}`. |
-| `tenant` | string | Required; matches advisory collection requirements. |
-| `source.*` | object | Same shape and requirements as `advisory_raw`. |
-| `upstream.*` | object | Includes `document_version`, timestamps, `content_hash`, and `signature`. |
-| `content.format` | string | Typically `CycloneDX-VEX` or `CSAF-VEX`. |
-| `content.raw` | object | Entire upstream VEX payload. |
-| `identifiers.statements` | array | Normalised statement summaries (IDs, PURLs, status, justification) to accelerate policy joins. |
-| `linkset` | object | CVEs, GHSA IDs, and PURLs referenced in the document. |
-| `supersedes` | string or null | Same convention as advisory documents. |
-
-### 4.3 Linkset Fields
-
-- `purls`: fully qualified Package URLs extracted from raw ranges or product nodes.
-- `cpes`: Common Platform Enumerations when upstream docs provide them.
-- `aliases`: Any alternate advisory identifiers present in the payload.
-- `references`: Array of `{ type, url }` pairs pointing back to vendor advisories, patches, or exploits.
-- `reconciled_from`: Provenance of linkset entries (JSON Pointer or field origin) to make automated checks auditable.
-
-Canonicalisation rules:
-- Package URLs are rendered in canonical form without qualifiers/subpaths (`pkg:type/namespace/name@version`).
-- CPE values are normalised to the 2.3 binding (`cpe:2.3:part:vendor:product:version:*:*:*:*:*:*:*`).
-- Connector mapping stages are responsible for the canonical form; ingestion trims whitespace but otherwise preserves the original order and duplicate entries so downstream policy can reason about upstream intent.
-
-### 4.4 `advisory_observations`
-
-`advisory_observations` is an immutable projection of the validated raw document used by Link‑Not‑Merge overlays. Fields mirror the JSON contract surfaced by `StellaOps.Concelier.Models.Observations.AdvisoryObservation`.
-
-| Field | Type | Notes |
-|-------|------|-------|
-| `_id` | string | Deterministic observation id — `{tenant}:{source.vendor}:{upstreamId}:{revision}`. |
-| `tenant` | string | Lower-case tenant identifier. |
-| `source.vendor` / `source.stream` | string | Connector identity (e.g., `vendor/redhat`, `ecosystem/osv`). |
-| `source.api` | string | Absolute URI the connector fetched from. |
-| `source.collectorVersion` | string | Optional semantic version of the connector build. |
-| `upstream.upstream_id` | string | Advisory identifier as issued by the provider (CVE, vendor ID, etc.). |
-| `upstream.document_version` | string | Upstream revision/version string. |
-| `upstream.fetchedAt` / `upstream.receivedAt` | datetime | UTC timestamps recorded by the connector. |
-| `upstream.contentHash` | string | `sha256:` digest used for idempotency. |
-| `upstream.signature` | object | `{present, format?, keyId?, signature?}` describing upstream signature material. |
-| `content.format` / `content.specVersion` | string | Raw payload format metadata (CSAF, OSV, JSON, etc.). |
-| `content.raw` | object | Full upstream document stored losslessly (Relaxed Extended JSON). |
-| `content.metadata` | object | Optional connector-specific metadata (batch ids, hints). |
-| `linkset.aliases` | array | Connector-supplied aliases (trimmed, order preserved, duplicates allowed). |
-| `linkset.purls` | array | Connector-supplied PURLs (ingestion preserves order and duplicates). |
-| `linkset.cpes` | array | Connector-supplied CPE URIs (trimmed, order preserved). |
-| `linkset.references` | array | `{ type, url }` pairs (trimmed; ingestion preserves order). |
-| `createdAt` | datetime | Timestamp when Concelier persisted the observation. |
-| `attributes` | object | Optional provenance attributes keyed by connector. |
-
-## 5. Error Model
-
-| Code | Description | HTTP status | Surfaces |
-|------|-------------|-------------|----------|
-| `ERR_AOC_001` | Forbidden field detected (severity, cvss, effective data). | 400 | Ingestion APIs, CLI verifier, CI guard. |
-| `ERR_AOC_002` | Merge attempt detected (multiple upstream sources fused into one document). | 400 | Ingestion APIs, CLI verifier. |
-| `ERR_AOC_003` | Idempotency violation (duplicate without supersedes pointer). | 409 | Repository guard, Mongo unique index, CLI verifier. |
-| `ERR_AOC_004` | Missing provenance metadata (`source`, `upstream`, `signature`). | 422 | Schema validator, ingestion endpoints. |
-| `ERR_AOC_005` | Signature or checksum mismatch. | 422 | Collector validation, CLI verifier. |
-| `ERR_AOC_006` | Attempt to persist derived findings from ingestion context. | 403 | Policy engine guard, Authority scopes. |
-| `ERR_AOC_007` | Unknown top-level fields (schema violation). | 400 | Mongo validator, CLI verifier. |
-
-Consumers should map these codes to CLI exit codes and structured log events so automation can fail fast and produce actionable guidance.
-
-## 6. API and Tooling Interfaces
-
-- **Concelier ingestion** (`StellaOps.Concelier.WebService`)
- - `POST /ingest/advisory`: accepts upstream payload metadata; server-side guard constructs and persists raw document.
- - `GET /advisories/raw/{id}` and filterable list endpoints expose raw documents for debugging and offline analysis.
- - `POST /aoc/verify`: runs guard checks over recent documents and returns summary totals plus first violations.
-- **Excititor ingestion** (`StellaOps.Excititor.WebService`) mirrors the same surface for VEX documents.
-- **CLI workflows** (`stella aoc verify`, `stella sources ingest --dry-run`) surface pre-flight verification; documentation will live in `/docs/modules/cli/guides/` alongside Sprint 19 CLI updates.
-- **Authority scopes**: new `advisory:ingest`, `advisory:read`, `vex:ingest`, and `vex:read` scopes enforce least privilege; see [Authority Architecture](../modules/authority/architecture.md) for scope grammar.
-
-## 7. Idempotency and Supersedes Rules
-
-1. Compute `content_hash` before any transformation; use it with `(source.vendor, upstream.upstream_id)` to detect duplicates.
-2. If a document with the same hash already exists, skip the write and log a no-op.
-3. When a new hash arrives for an existing upstream document, insert a new record and set `supersedes` to the previous `_id`.
-4. Keep supersedes chains acyclic; collectors must resolve conflicts by rewinding before they insert.
-5. Expose idempotency counters via metrics (`ingestion_write_total{result=ok|noop}`) to catch regressions early.
-
-## 8. Migration Playbook
-
-1. Freeze ingestion writes except for raw pass-through paths while deploying schema validators.
-2. Snapshot existing collections to `_backup_*` for rollback safety.
-3. Strip forbidden fields from historical documents into a temporary `advisory_view_legacy` used only during transition.
-4. Enable Mongo JSON schema validators for `advisory_raw` and `vex_raw`.
-5. Run collectors in `--dry-run` to confirm only allowed keys appear; fix violations before lifting the freeze.
-6. Point Policy Engine to consume exclusively from raw collections and compute derived outputs downstream.
-7. Delete legacy normalisation paths from ingestion code and enable runtime guards plus CI linting.
-8. Roll forward CLI, Console, and dashboards so operators can monitor AOC status end-to-end.
-
-## 9. Observability and Diagnostics
-
-- **Metrics**: `ingestion_write_total{result=ok|reject}`, `aoc_violation_total{code}`, `ingestion_signature_verified_total{result}`, `ingestion_latency_seconds`, `advisory_revision_count`.
-- **Traces**: spans `ingest.fetch`, `ingest.transform`, `ingest.write`, and `aoc.guard` with correlation IDs shared across workers.
-- **Logs**: structured entries must include `tenant`, `source.vendor`, `upstream.upstream_id`, `content_hash`, and `violation_code` when applicable.
-- **Dashboards**: DevOps should add panels for violation counts, signature failures, supersedes growth, and CLI verifier outcomes for each tenant.
-
-## 10. Security and Tenancy Checklist
-
-- Enforce Authority scopes (`advisory:ingest`, `vex:ingest`, `advisory:read`, `vex:read`) and require tenant claims on every request.
-- Maintain pinned trust stores for signature verification; capture verification result in metrics and logs.
-- Ensure collectors never log secrets or raw authentication headers; redact tokens before persistence.
-- Validate that Policy Engine remains the only identity with permission to write `effective_finding_*` documents.
-- Verify offline bundles include the raw collections, guard configuration, and verifier binaries so air-gapped installs can audit parity.
-- Document operator steps for recovering from violations, including rollback to superseded revisions and re-running policy evaluation.
-
-## 11. Compliance Checklist
-
-- [ ] Deterministic guard enabled in Concelier and Excititor repositories.
-- [ ] Mongo validators deployed for `advisory_raw` and `vex_raw`.
-- [ ] Authority scopes and tenant enforcement verified via integration tests.
-- [ ] CLI and CI pipelines run `stella aoc verify` against seeded snapshots.
-- [ ] Observability feeds (metrics, logs, traces) wired into dashboards with alerts.
-- [ ] Offline kit instructions updated to bundle validators and verifier tooling.
-- [ ] Security review recorded covering ingestion, tenancy, and rollback procedures.
-
----
-
-*Last updated: 2025-10-27 (Sprint 19).*
\ No newline at end of file
+
+## 2. Philosophy and Goals
+
+- Preserve upstream truth: ingestion only captures immutable raw facts plus provenance, never derived severity or policy decisions.
+- Defer interpretation: Policy Engine and downstream overlays remain the sole writers of materialised findings, severity, consensus, or risk scores.
+- Make every write explainable: provenance, signatures, and content hashes are required so operators can prove where each fact originated.
+- Keep outputs reproducible: identical inputs must yield identical documents, hashes, and linksets across replays and air-gapped installs.
+
+## 3. Contract Invariants
+
+| # | Invariant | What it forbids or requires | Enforcement surfaces |
+|---|-----------|-----------------------------|----------------------|
+| 1 | No derived severity at ingest | Reject top-level keys such as `severity`, `cvss`, `effective_status`, `consensus_provider`, `risk_score`. Raw upstream CVSS remains inside `content.raw`. | Mongo schema validator, `AOCWriteGuard`, Roslyn analyzer, `stella aoc verify`. |
+| 2 | No merges or opinionated dedupe | Each upstream document persists on its own; ingestion never collapses multiple vendors into one document. | Repository interceptors, unit/fixture suites. |
+| 3 | Provenance is mandatory | `source.*`, `upstream.*`, and `signature` metadata must be present; missing provenance triggers `ERR_AOC_004`. | Schema validator, guard, CLI verifier. |
+| 4 | Idempotent upserts | Writes keyed by `(vendor, upstream_id, content_hash)` either no-op or insert a new revision with `supersedes`. Duplicate hashes map to the same document. | Repository guard, storage unique index, CI smoke tests. |
+| 5 | Append-only revisions | Updates create a new document with `supersedes` pointer; no in-place mutation of content. | Mongo schema (`supersedes` format), guard, data migration scripts. |
+| 6 | Linkset only | Ingestion may compute link hints (`purls`, `cpes`, IDs) to accelerate joins, but must not transform or infer severity or policy. Observations now persist both canonical linksets (for indexed queries) and raw linksets (preserving upstream order/duplicates) so downstream policy can decide how to normalise. When `concelier:features:noMergeEnabled=true`, all merge-derived canonicalisation paths must be disabled. | Linkset builders reviewed via fixtures/analyzers; raw-vs-canonical parity covered by observation fixtures; analyzer `CONCELIER0002` blocks merge API usage. |
+| 7 | Policy-only effective findings | Only Policy Engine identities can write `effective_finding_*`; ingestion callers receive `ERR_AOC_006` if they attempt it. | Authority scopes, Policy Engine guard. |
+| 8 | Schema safety | Unknown top-level keys reject with `ERR_AOC_007`; timestamps use ISO 8601 UTC strings; tenant is required. | Mongo validator, JSON schema tests. |
+| 9 | Clock discipline | Collectors stamp `fetched_at` and `received_at` monotonically per batch to support reproducibility windows. | Collector contracts, QA fixtures. |
+
+## 4. Raw Schemas
+
+### 4.1 `advisory_raw`
+
+| Field | Type | Notes |
+|-------|------|-------|
+| `_id` | string | `advisory_raw:{source}:{upstream_id}:{revision}`; deterministic and tenant-scoped. |
+| `tenant` | string | Required; injected by Authority middleware and asserted by schema validator. |
+| `source.vendor` | string | Provider identifier (e.g., `redhat`, `osv`, `ghsa`). |
+| `source.stream` | string | Connector stream name (`csaf`, `osv`, etc.). |
+| `source.api` | string | Absolute URI of upstream document; stored for traceability. |
+| `source.collector_version` | string | Semantic version of the collector. |
+| `upstream.upstream_id` | string | Vendor- or ecosystem-provided identifier (CVE, GHSA, vendor ID). |
+| `upstream.document_version` | string | Upstream issued timestamp or revision string. |
+| `upstream.fetched_at` / `received_at` | string | ISO 8601 UTC timestamps recorded by the collector. |
+| `upstream.content_hash` | string | `sha256:` digest of the raw payload used for idempotency. |
+| `upstream.signature` | object | Required structure storing `present`, `format`, `key_id`, `sig`; even unsigned payloads set `present: false`. |
+| `content.format` | string | Source format (`CSAF`, `OSV`, etc.). |
+| `content.spec_version` | string | Upstream spec version when known. |
+| `content.raw` | object | Full upstream payload, untouched except for transport normalisation. |
+| `identifiers` | object | Upstream identifiers (`cve`, `ghsa`, `aliases`, etc.) captured as provided (trimmed, order preserved, duplicates allowed). |
+| `linkset` | object | Join hints (see section 4.3). |
+| `supersedes` | string or null | Points to previous revision of same upstream doc when content hash changes. |
+
+### 4.2 `vex_raw`
+
+| Field | Type | Notes |
+|-------|------|-------|
+| `_id` | string | `vex_raw:{source}:{upstream_id}:{revision}`. |
+| `tenant` | string | Required; matches advisory collection requirements. |
+| `source.*` | object | Same shape and requirements as `advisory_raw`. |
+| `upstream.*` | object | Includes `document_version`, timestamps, `content_hash`, and `signature`. |
+| `content.format` | string | Typically `CycloneDX-VEX` or `CSAF-VEX`. |
+| `content.raw` | object | Entire upstream VEX payload. |
+| `identifiers.statements` | array | Normalised statement summaries (IDs, PURLs, status, justification) to accelerate policy joins. |
+| `linkset` | object | CVEs, GHSA IDs, and PURLs referenced in the document. |
+| `supersedes` | string or null | Same convention as advisory documents. |
+
+### 4.3 Linkset Fields
+
+- `purls`: fully qualified Package URLs extracted from raw ranges or product nodes.
+- `cpes`: Common Platform Enumerations when upstream docs provide them.
+- `aliases`: Any alternate advisory identifiers present in the payload.
+- `references`: Array of `{ type, url }` pairs pointing back to vendor advisories, patches, or exploits.
+- `reconciled_from`: Provenance of linkset entries (JSON Pointer or field origin) to make automated checks auditable.
+
+Canonicalisation rules:
+- Package URLs are rendered in canonical form without qualifiers/subpaths (`pkg:type/namespace/name@version`).
+- CPE values are normalised to the 2.3 binding (`cpe:2.3:part:vendor:product:version:*:*:*:*:*:*:*`).
+- Connector mapping stages are responsible for the canonical form; ingestion trims whitespace but otherwise preserves the original order and duplicate entries so downstream policy can reason about upstream intent.
+
+### 4.4 `advisory_observations`
+
+`advisory_observations` is an immutable projection of the validated raw document used by Link‑Not‑Merge overlays. Fields mirror the JSON contract surfaced by `StellaOps.Concelier.Models.Observations.AdvisoryObservation`.
+
+| Field | Type | Notes |
+|-------|------|-------|
+| `_id` | string | Deterministic observation id — `{tenant}:{source.vendor}:{upstreamId}:{revision}`. |
+| `tenant` | string | Lower-case tenant identifier. |
+| `source.vendor` / `source.stream` | string | Connector identity (e.g., `vendor/redhat`, `ecosystem/osv`). |
+| `source.api` | string | Absolute URI the connector fetched from. |
+| `source.collectorVersion` | string | Optional semantic version of the connector build. |
+| `upstream.upstream_id` | string | Advisory identifier as issued by the provider (CVE, vendor ID, etc.). |
+| `upstream.document_version` | string | Upstream revision/version string. |
+| `upstream.fetchedAt` / `upstream.receivedAt` | datetime | UTC timestamps recorded by the connector. |
+| `upstream.contentHash` | string | `sha256:` digest used for idempotency. |
+| `upstream.signature` | object | `{present, format?, keyId?, signature?}` describing upstream signature material. |
+| `content.format` / `content.specVersion` | string | Raw payload format metadata (CSAF, OSV, JSON, etc.). |
+| `content.raw` | object | Full upstream document stored losslessly (Relaxed Extended JSON). |
+| `content.metadata` | object | Optional connector-specific metadata (batch ids, hints). |
+| `linkset.aliases` | array | Connector-supplied aliases (trimmed, order preserved, duplicates allowed). |
+| `linkset.purls` | array | Connector-supplied PURLs (ingestion preserves order and duplicates). |
+| `linkset.cpes` | array | Connector-supplied CPE URIs (trimmed, order preserved). |
+| `linkset.references` | array | `{ type, url }` pairs (trimmed; ingestion preserves order). |
+| `createdAt` | datetime | Timestamp when Concelier persisted the observation. |
+| `attributes` | object | Optional provenance attributes keyed by connector. |
+
+## 5. Error Model
+
+| Code | Description | HTTP status | Surfaces |
+|------|-------------|-------------|----------|
+| `ERR_AOC_001` | Forbidden field detected (severity, cvss, effective data). | 400 | Ingestion APIs, CLI verifier, CI guard. |
+| `ERR_AOC_002` | Merge attempt detected (multiple upstream sources fused into one document). | 400 | Ingestion APIs, CLI verifier. |
+| `ERR_AOC_003` | Idempotency violation (duplicate without supersedes pointer). | 409 | Repository guard, Mongo unique index, CLI verifier. |
+| `ERR_AOC_004` | Missing provenance metadata (`source`, `upstream`, `signature`). | 422 | Schema validator, ingestion endpoints. |
+| `ERR_AOC_005` | Signature or checksum mismatch. | 422 | Collector validation, CLI verifier. |
+| `ERR_AOC_006` | Attempt to persist derived findings from ingestion context. | 403 | Policy engine guard, Authority scopes. |
+| `ERR_AOC_007` | Unknown top-level fields (schema violation). | 400 | Mongo validator, CLI verifier. |
+
+Consumers should map these codes to CLI exit codes and structured log events so automation can fail fast and produce actionable guidance.
+
+## 6. API and Tooling Interfaces
+
+- **Concelier ingestion** (`StellaOps.Concelier.WebService`)
+ - `POST /ingest/advisory`: accepts upstream payload metadata; server-side guard constructs and persists raw document.
+ - `GET /advisories/raw/{id}` and filterable list endpoints expose raw documents for debugging and offline analysis.
+ - `POST /aoc/verify`: runs guard checks over recent documents and returns summary totals plus first violations.
+- **Excititor ingestion** (`StellaOps.Excititor.WebService`) mirrors the same surface for VEX documents.
+- **CLI workflows** (`stella aoc verify`, `stella sources ingest --dry-run`) surface pre-flight verification; documentation will live in `/docs/modules/cli/guides/` alongside Sprint 19 CLI updates.
+- **Authority scopes**: new `advisory:ingest`, `advisory:read`, `vex:ingest`, and `vex:read` scopes enforce least privilege; see [Authority Architecture](../modules/authority/architecture.md) for scope grammar.
+
+## 7. Idempotency and Supersedes Rules
+
+1. Compute `content_hash` before any transformation; use it with `(source.vendor, upstream.upstream_id)` to detect duplicates.
+2. If a document with the same hash already exists, skip the write and log a no-op.
+3. When a new hash arrives for an existing upstream document, insert a new record and set `supersedes` to the previous `_id`.
+4. Keep supersedes chains acyclic; collectors must resolve conflicts by rewinding before they insert.
+5. Expose idempotency counters via metrics (`ingestion_write_total{result=ok|noop}`) to catch regressions early.
+
+## 8. Migration Playbook
+
+1. Freeze ingestion writes except for raw pass-through paths while deploying schema validators.
+2. Snapshot existing collections to `_backup_*` for rollback safety.
+3. Strip forbidden fields from historical documents into a temporary `advisory_view_legacy` used only during transition.
+4. Enable Mongo JSON schema validators for `advisory_raw` and `vex_raw`.
+5. Run collectors in `--dry-run` to confirm only allowed keys appear; fix violations before lifting the freeze.
+6. Point Policy Engine to consume exclusively from raw collections and compute derived outputs downstream.
+7. Delete legacy normalisation paths from ingestion code and enable runtime guards plus CI linting.
+8. Roll forward CLI, Console, and dashboards so operators can monitor AOC status end-to-end.
+
+## 9. Observability and Diagnostics
+
+- **Metrics**: `ingestion_write_total{result=ok|reject}`, `aoc_violation_total{code}`, `ingestion_signature_verified_total{result}`, `ingestion_latency_seconds`, `advisory_revision_count`.
+- **Traces**: spans `ingest.fetch`, `ingest.transform`, `ingest.write`, and `aoc.guard` with correlation IDs shared across workers.
+- **Logs**: structured entries must include `tenant`, `source.vendor`, `upstream.upstream_id`, `content_hash`, and `violation_code` when applicable.
+- **Dashboards**: DevOps should add panels for violation counts, signature failures, supersedes growth, and CLI verifier outcomes for each tenant.
+
+## 10. Security and Tenancy Checklist
+
+- Enforce Authority scopes (`advisory:ingest`, `vex:ingest`, `advisory:read`, `vex:read`) and require tenant claims on every request.
+- Maintain pinned trust stores for signature verification; capture verification result in metrics and logs.
+- Ensure collectors never log secrets or raw authentication headers; redact tokens before persistence.
+- Validate that Policy Engine remains the only identity with permission to write `effective_finding_*` documents.
+- Verify offline bundles include the raw collections, guard configuration, and verifier binaries so air-gapped installs can audit parity.
+- Document operator steps for recovering from violations, including rollback to superseded revisions and re-running policy evaluation.
+
+## 11. Compliance Checklist
+
+- [ ] Deterministic guard enabled in Concelier and Excititor repositories.
+- [ ] Mongo validators deployed for `advisory_raw` and `vex_raw`.
+- [ ] Authority scopes and tenant enforcement verified via integration tests.
+- [ ] CLI and CI pipelines run `stella aoc verify` against seeded snapshots.
+- [ ] Observability feeds (metrics, logs, traces) wired into dashboards with alerts.
+- [ ] Offline kit instructions updated to bundle validators and verifier tooling.
+- [ ] Security review recorded covering ingestion, tenancy, and rollback procedures.
+
+---
+
+*Last updated: 2025-10-27 (Sprint 19).*
diff --git a/docs/migration/no-merge.md b/docs/migration/no-merge.md
index 5ba6cd43c..76ca319ef 100644
--- a/docs/migration/no-merge.md
+++ b/docs/migration/no-merge.md
@@ -1,6 +1,6 @@
# No-Merge Migration Playbook
-_Last updated: 2025-11-03_
+_Last updated: 2025-11-06_
This playbook guides the full retirement of the legacy Merge service (`AdvisoryMergeService`) in favour of Link-Not-Merge (LNM) observations plus linksets. It is written for the BE-Merge, Architecture, DevOps, and Docs guilds coordinating Sprint 110 (Ingestion & Evidence) deliverables, and it feeds CONCELIER-LNM-21-101 / MERGE-LNM-21-001 and downstream DOCS-LNM-22-008.
@@ -35,6 +35,10 @@ Do not proceed to Phase 1 until all prerequisites are checked or explicitly wa
| `concelier:jobs:merge:allowlist` | `[]` | Explicit allowlist for Merge jobs when noMergeEnabled is `false`. | Set to empty during Phase 2+ to prevent accidental restarts. |
| `policy:overlays:requireLinksetEvidence` | `false` | Policy engine safety net to require linkset-backed findings. | Flip to `true` only after cutover (Phase 2). |
+> 2025-11-05: WebService honours `concelier:features:noMergeEnabled` by skipping Merge DI registration and removing the `merge:reconcile` job definition (MERGE-LNM-21-002).
+>
+> 2025-11-06: Analyzer `CONCELIER0002` ships with Concelier hosts to block new references to `AdvisoryMergeService` / `AddMergeModule`. Suppressions must be paired with an explicit migration note.
+
> **Configuration hygiene:** Document the toggle values per environment in `ops/devops/configuration/staging.md` and `ops/devops/configuration/production.md`. Air-gapped customers receive defaults through the Offline Kit release notes.
## 3. Rollout phases
diff --git a/docs/modules/attestor/README.md b/docs/modules/attestor/README.md
index ceebaa030..1f99d5b44 100644
--- a/docs/modules/attestor/README.md
+++ b/docs/modules/attestor/README.md
@@ -1,11 +1,14 @@
# StellaOps Attestor
-Attestor converts signed DSSE evidence from the Signer into transparency-log proofs and verifiable reports for every downstream surface (Policy Engine, Export Center, CLI, Console, Scheduler). It is the trust backbone that proves SBOM, scan, VEX, and policy artefacts were signed, witnessed, and preserved without tampering.
-
-## Why it exists
-- **Evidence first:** organisations need portable, verifiable attestations that prove build provenance, SBOM availability, policy verdicts, and VEX statements.
-- **Policy enforcement:** verification policies ensure only approved issuers, key types, witnesses, and freshness windows are accepted.
-- **Sovereign/offline-ready:** Attestor archives envelopes, signatures, and proofs so air-gapped deployments can replay verification without contacting external services.
+Attestor converts signed DSSE evidence from the Signer into transparency-log proofs and verifiable reports for every downstream surface (Policy Engine, Export Center, CLI, Console, Scheduler). It is the trust backbone that proves SBOM, scan, VEX, and policy artefacts were signed, witnessed, and preserved without tampering.
+
+## Latest updates (2025-10-19)
+- Platform Events refresh published canonical `attestor.logged@1` samples under `docs/events/samples/` and validated schemas (`docs/updates/2025-10-18-docs-guild.md`, `docs/updates/2025-10-19-docs-guild.md`). Consumers should align verification workflows and tests with those sample envelopes.
+
+## Why it exists
+- **Evidence first:** organisations need portable, verifiable attestations that prove build provenance, SBOM availability, policy verdicts, and VEX statements.
+- **Policy enforcement:** verification policies ensure only approved issuers, key types, witnesses, and freshness windows are accepted.
+- **Sovereign/offline-ready:** Attestor archives envelopes, signatures, and proofs so air-gapped deployments can replay verification without contacting external services.
## Roles & surfaces
- **Subjects:** immutable digests for container images, SBOMs, reports, and policy bundles.
diff --git a/docs/modules/attestor/TASKS.md b/docs/modules/attestor/TASKS.md
index 2fd8aab05..58d6dcb97 100644
--- a/docs/modules/attestor/TASKS.md
+++ b/docs/modules/attestor/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| ATTESTOR-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| ATTESTOR-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now references 2025-10-18/19 platform-event updates and the canonical `attestor.logged@1` samples. |
| ATTESTOR-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| ATTESTOR-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/concelier/README.md b/docs/modules/concelier/README.md
index 7c89cdb46..8985175e1 100644
--- a/docs/modules/concelier/README.md
+++ b/docs/modules/concelier/README.md
@@ -18,19 +18,22 @@ Concelier ingests signed advisories from dozens of sources and converts them int
- Policy Engine / Export Center / CLI for evidence consumption.
- Notify and UI for advisory deltas.
-## Operational notes
-- Connector runbooks in ./operations/connectors/.
-- Mirror operations for Offline Kit parity.
-- Grafana dashboards for connector health.
-
-## Related resources
-- ./operations/conflict-resolution.md
-- ./operations/mirror.md
-
-## Backlog references
-- DOCS-LNM-22-001, DOCS-LNM-22-007 in ../../TASKS.md.
-- Connector-specific TODOs in `src/Concelier/**/TASKS.md`.
-
+## Operational notes
+- Connector runbooks in ./operations/connectors/.
+- Mirror operations for Offline Kit parity.
+- Grafana dashboards for connector health.
+- **Authority toggle rollout (2025-10-22 update).** Follow the phased table and audit checklist in `../../10_CONCELIER_CLI_QUICKSTART.md` when enabling `authority.enabled`/`authority.allowAnonymousFallback`, and cross-check the refreshed `./operations/authority-audit-runbook.md` before enforcement.
+
+## Related resources
+- ./operations/conflict-resolution.md
+- ./operations/mirror.md
+- ./operations/authority-audit-runbook.md
+- ../../10_CONCELIER_CLI_QUICKSTART.md (authority integration timeline & smoke tests)
+
+## Backlog references
+- DOCS-LNM-22-001, DOCS-LNM-22-007 in ../../TASKS.md.
+- Connector-specific TODOs in `src/Concelier/**/TASKS.md`.
+
## Epic alignment
- **Epic 1 – AOC enforcement:** uphold raw observation invariants, provenance requirements, linkset-only enrichment, and AOC verifier guardrails across every connector.
- **Epic 10 – Export Center:** expose deterministic advisory exports and metadata required by JSON/Trivy/mirror bundles.
diff --git a/docs/modules/concelier/TASKS.md b/docs/modules/concelier/TASKS.md
index d08e7cc46..6d74efa7c 100644
--- a/docs/modules/concelier/TASKS.md
+++ b/docs/modules/concelier/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| CONCELIER-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| CONCELIER-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now references the 2025-10-22 authority toggle rollout update (quickstart/runbook links). |
| CONCELIER-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| CONCELIER-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/concelier/architecture.md b/docs/modules/concelier/architecture.md
index 25c245ed2..f18b44b37 100644
--- a/docs/modules/concelier/architecture.md
+++ b/docs/modules/concelier/architecture.md
@@ -27,10 +27,12 @@
3. **Mandatory provenance.** Collectors record `source`, `upstream` metadata (`document_version`, `fetched_at`, `received_at`, `content_hash`), and signature presence before writing.
4. **Linkset only.** Derived joins (aliases, PURLs, CPEs, references) are stored inside `linkset` and never mutate `content.raw`.
5. **Deterministic canonicalisation.** Writers use canonical JSON (sorted object keys, lexicographic arrays) ensuring identical inputs yield the same hashes/diff-friendly outputs.
-6. **Idempotent upserts.** `(source.vendor, upstream.upstream_id, upstream.content_hash)` uniquely identify a document. Duplicate hashes short-circuit; new hashes create a new version.
-7. **Verifier & CI.** `StellaOps.AOC.Verifier` processes observation batches in CI and at runtime, rejecting writes lacking provenance, introducing unordered collections, or violating the schema.
-
-### 1.1 Advisory raw document shape
+6. **Idempotent upserts.** `(source.vendor, upstream.upstream_id, upstream.content_hash)` uniquely identify a document. Duplicate hashes short-circuit; new hashes create a new version.
+7. **Verifier & CI.** `StellaOps.AOC.Verifier` processes observation batches in CI and at runtime, rejecting writes lacking provenance, introducing unordered collections, or violating the schema.
+
+> Feature toggle: set `concelier:features:noMergeEnabled=true` to disable the legacy Merge module and its `merge:reconcile` job once Link-Not-Merge adoption is complete (MERGE-LNM-21-002). Analyzer `CONCELIER0002` prevents new references to Merge DI helpers when this flag is enabled.
+
+### 1.1 Advisory raw document shape
```json
{
diff --git a/docs/modules/excititor/README.md b/docs/modules/excititor/README.md
index 5f9b9715a..de7c9ce71 100644
--- a/docs/modules/excititor/README.md
+++ b/docs/modules/excititor/README.md
@@ -1,33 +1,37 @@
-# StellaOps Excititor
-
-Excititor converts heterogeneous VEX feeds into raw observations and linksets that honour the Aggregation-Only Contract.
-
-## Responsibilities
-- Fetch OpenVEX/CSAF/CycloneDX statements via restart-only connectors.
-- Store immutable VEX observations with full provenance.
-- Publish linksets and events that drive policy suppression decisions.
-- Provide deterministic exports for Offline Kit and downstream tooling.
-
-## Key components
-- `StellaOps.Excititor.WebService` scheduler/API host.
-- Connector libraries under `StellaOps.Excititor.Connector.*`.
-- Normalization helpers and exporters in `StellaOps.Excititor.*`.
-
-## Integrations & dependencies
-- Policy Engine for evidence queries.
-- UI/CLI for conflict visibility and explanation.
-- Notify for VEX-driven alerts.
-
-## Operational notes
-- MongoDB for observation storage and job metadata.
-- Offline kit packaging aligned with Concelier merges.
-- Connector-specific runbooks (see `docs/modules/concelier/operations/connectors`).
-
-## Backlog references
-- DOCS-LNM-22-006 / DOCS-LNM-22-007 (shared with Concelier).
-- CLI-EXC-25-001..002 follow-up for CLI parity.
-
-## Epic alignment
-- **Epic 1 – AOC enforcement:** maintain immutable VEX observations, provenance, and AOC verifier coverage.
-- **Epic 7 – VEX Consensus Lens:** supply trustworthy raw inputs, trust metadata, and consensus hooks for the lens computations.
-- **Epic 8 – Advisory AI:** expose citation-ready VEX payloads for the advisory assistant pipeline.
+# StellaOps Excititor
+
+Excititor converts heterogeneous VEX feeds into raw observations and linksets that honour the Aggregation-Only Contract.
+
+## Latest updates (2025-11-05)
+- Link-Not-Merge readiness: release note [Excitor consensus beta](../../updates/2025-11-05-excitor-consensus-beta.md) captures how Excititor feeds power the Excitor consensus beta (sample payload in [consensus JSON](../../vex/consensus-json.md)).
+- README now points policy/UI teams to the upcoming consensus integration work.
+
+## Responsibilities
+- Fetch OpenVEX/CSAF/CycloneDX statements via restart-only connectors.
+- Store immutable VEX observations with full provenance.
+- Publish linksets and events that drive policy suppression decisions.
+- Provide deterministic exports for Offline Kit and downstream tooling.
+
+## Key components
+- `StellaOps.Excititor.WebService` scheduler/API host.
+- Connector libraries under `StellaOps.Excititor.Connector.*`.
+- Normalization helpers and exporters in `StellaOps.Excititor.*`.
+
+## Integrations & dependencies
+- Policy Engine for evidence queries.
+- UI/CLI for conflict visibility and explanation.
+- Notify for VEX-driven alerts.
+
+## Operational notes
+- MongoDB for observation storage and job metadata.
+- Offline kit packaging aligned with Concelier merges.
+- Connector-specific runbooks (see `docs/modules/concelier/operations/connectors`).
+
+## Backlog references
+- DOCS-LNM-22-006 / DOCS-LNM-22-007 (shared with Concelier).
+- CLI-EXC-25-001..002 follow-up for CLI parity.
+
+## Epic alignment
+- **Epic 1 – AOC enforcement:** maintain immutable VEX observations, provenance, and AOC verifier coverage.
+- **Epic 7 – VEX Consensus Lens:** supply trustworthy raw inputs, trust metadata, and consensus hooks for the lens computations.
+- **Epic 8 – Advisory AI:** expose citation-ready VEX payloads for the advisory assistant pipeline.
diff --git a/docs/modules/excititor/TASKS.md b/docs/modules/excititor/TASKS.md
index 8e814931c..2cc0afe27 100644
--- a/docs/modules/excititor/TASKS.md
+++ b/docs/modules/excititor/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| EXCITITOR-DOCS-0001 | TODO | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| EXCITITOR-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now links to the [Excitor consensus beta release note](../../updates/2025-11-05-excitor-consensus-beta.md) and [consensus JSON sample](../../vex/consensus-json.md). |
| EXCITITOR-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| EXCITITOR-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/excitor/README.md b/docs/modules/excitor/README.md
index 59e40ec5e..302076517 100644
--- a/docs/modules/excitor/README.md
+++ b/docs/modules/excitor/README.md
@@ -2,6 +2,10 @@
Excitor computes deterministic consensus across VEX claims, preserving conflicts and producing attestable evidence for policy suppression.
+## Latest updates (2025-11-05)
+- Consensus API beta documented with canonical JSON samples and DSSE packaging guidance (`docs/updates/2025-11-05-excitor-consensus-beta.md`).
+- README links to Link-Not-Merge consensus milestone and preview endpoints for downstream integration.
+
## Responsibilities
- Ingest Excititor observations and compute per-product consensus snapshots.
- Provide APIs for querying canonical VEX positions and conflict sets.
@@ -25,6 +29,7 @@ Excitor computes deterministic consensus across VEX claims, preserving conflicts
## Related resources
- ./scoring.md
+- ../../vex/consensus-json.md (beta consensus payload sample)
## Backlog references
- DOCS-EXCITOR backlog referenced in architecture doc.
diff --git a/docs/modules/excitor/TASKS.md b/docs/modules/excitor/TASKS.md
index d13c519fa..2245d0578 100644
--- a/docs/modules/excitor/TASKS.md
+++ b/docs/modules/excitor/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| EXCITOR-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| EXCITOR-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now references the 2025-11-05 consensus API beta release note (`docs/updates/2025-11-05-excitor-consensus-beta.md`). |
| EXCITOR-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| EXCITOR-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/export-center/README.md b/docs/modules/export-center/README.md
index 7c5dfc449..19afe09d5 100644
--- a/docs/modules/export-center/README.md
+++ b/docs/modules/export-center/README.md
@@ -8,27 +8,35 @@ Export Center packages reproducible evidence bundles (JSON, Trivy DB, mirror) wi
- Stream bundles via HTTP/OCI and stage them for Offline Kit uses.
- Expose CLI/API surfaces for automation.
-## Key components
-- `StellaOps.ExportCenter.WebService` planner.
-- `StellaOps.ExportCenter.Worker` bundle builder.
-- Adapters in `StellaOps.ExportCenter.*` for JSON/Trivy/mirror variants.
-
-## Integrations & dependencies
-- Concelier/Excititor/Policy data stores for evidence.
-- Signer/Attestor for provenance signing.
-- CLI for operator-managed exports.
-
+## Key components
+- `StellaOps.ExportCenter.WebService` planner.
+- `StellaOps.ExportCenter.Worker` bundle builder.
+- Adapters in `StellaOps.ExportCenter.*` for JSON/Trivy/mirror variants.
+
+## Profiles at a glance
+- **json:raw / json:policy** — Evidence bundles with raw ingestion facts or policy overlays.
+- **trivy:db / trivy:java-db** — Trivy-compatible vulnerability feeds with deterministic manifests.
+- **mirror:full / mirror:delta** — OCI-style mirrors with provenance, TUF metadata, and optional encryption.
+- **devportal:offline** — Developer portal static assets, specs, SDKs, and changelogs packaged with `manifest.json`, `checksums.txt`, helper scripts, and a DSSE-signed manifest (`manifest.dsse.json`) for offline verification.
+
+## Integrations & dependencies
+- Concelier/Excititor/Policy data stores for evidence.
+- Signer/Attestor for provenance signing.
+- CLI for operator-managed exports.
+
## Operational notes
- Runbooks in ./operations/ for deployment and monitoring.
- Mirror bundle instructions and validation notes.
- Telemetry dashboards for export latency and retry rates.
-
-## Related resources
-- ./operations/runbook.md
-
-## Backlog references
-- DOCS-EXPORT-35-001 … DOCS-EXPORT-37-002 in ../../TASKS.md.
-- EXPORT-ATTEST-75-002 cross-team deliverable.
-
+
+## Related resources
+- ./operations/runbook.md
+- ./devportal-offline.md (bundle structure, verification workflow, DSSE signature details)
+- ./provenance-and-signing.md (manifest/provenance schema, signing pipeline, verification)
+
+## Backlog references
+- DOCS-EXPORT-35-001 … DOCS-EXPORT-37-002 in ../../TASKS.md.
+- EXPORT-ATTEST-75-002 cross-team deliverable.
+
## Epic alignment
- **Epic 10 – Export Center:** deliver canonical JSON, Trivy DB, and mirror bundle workflows with provenance, signatures, and offline parity.
diff --git a/docs/modules/export-center/TASKS.md b/docs/modules/export-center/TASKS.md
index 44184563e..de81d150f 100644
--- a/docs/modules/export-center/TASKS.md
+++ b/docs/modules/export-center/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| EXPORT CENTER-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| EXPORT CENTER-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now documents devportal offline profile, DSSE manifest signature, and links to supporting specs per 2025-10-29 release update. |
| EXPORT CENTER-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| EXPORT CENTER-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/export-center/architecture.md b/docs/modules/export-center/architecture.md
index 109f6e8c3..581a3a23a 100644
--- a/docs/modules/export-center/architecture.md
+++ b/docs/modules/export-center/architecture.md
@@ -84,7 +84,8 @@ All endpoints require Authority-issued JWT + DPoP tokens with scopes `export:run
- Supports optional encryption of `/data` subtree (age/AES-GCM) with key wrapping stored in `provenance.json`.
- **DevPortal (`devportal:offline`).**
- Packages developer portal static assets, OpenAPI specs, SDK releases, and changelog content into a reproducible archive with manifest/checksum pairs.
- - Emits `manifest.json`, `checksums.txt`, and helper scripts described in [DevPortal Offline Bundle Specification](devportal-offline.md); signing/DSSE wiring follows the shared Export Center signing service.
+ - Emits `manifest.json`, `checksums.txt`, helper scripts, and a DSSE signature document (`manifest.dsse.json`) as described in [DevPortal Offline Bundle Specification](devportal-offline.md).
+ - Stores artefacts under `//` and signs manifests via the Export Center signing adapter (HMAC-SHA256 v1, tenant scoped).
Adapters expose structured telemetry events (`adapter.start`, `adapter.chunk`, `adapter.complete`) with record counts and byte totals per chunk. Failures emit `adapter.error` with reason codes.
diff --git a/docs/modules/export-center/devportal-offline.md b/docs/modules/export-center/devportal-offline.md
index 05513137a..088bf355e 100644
--- a/docs/modules/export-center/devportal-offline.md
+++ b/docs/modules/export-center/devportal-offline.md
@@ -81,7 +81,14 @@ root
The `root` value is the SHA-256 hash of the serialized manifest and is exposed separately in the result object for downstream signing.
-## 4. Verification script
+## 4. DSSE signature and storage
+
+- The export job signs `manifest.json` with an HMAC-SHA256 based DSSE envelope, producing `manifest.dsse.json` alongside the bundle artefacts.
+- The signature document captures the bundle identifier, manifest root hash, signing timestamp, algorithm metadata, and the DSSE payload/signature.
+- Operators verify the manifest by validating `manifest.dsse.json`, then cross-checking the `payload` base64 with the downloaded manifest and the `rootHash` in `checksums.txt`.
+- All artefacts are written under a deterministic storage prefix `//` with the bundle archive stored as `bundle.tgz` (or the configured file name).
+
+## 5. Verification script
`verify-offline.sh` is a POSIX-compatible helper that:
@@ -91,7 +98,7 @@ The `root` value is the SHA-256 hash of the serialized manifest and is exposed s
Operators can override the archive name via the first argument (`./verify-offline.sh mybundle.tgz`).
-## 5. Content categories
+## 6. Content categories
| Category | Target prefix | Notes |
|-----------|---------------|-------|
@@ -102,14 +109,13 @@ Operators can override the archive name via the first argument (`./verify-offlin
Paths are normalised to forward slashes and guarded against directory traversal.
-## 6. Determinism and hashing rules
+## 7. Determinism and hashing rules
- Files are enumerated and emitted in ordinal path order.
- SHA-256 digests use lowercase hex encoding.
- Optional directories (specs, SDKs, changelog) are skipped when absent; at least one category must contain files or the builder fails fast.
-## 7. Next steps
+## 8. Next steps
-- Attach DSSE signing + timestamping (`signature.json`) once Export Center signing infrastructure is ready.
-- Integrate the builder into the Export Center worker profile (`devportal --offline`) and plumb orchestration/persistence.
-- Produce CLI validation tooling (`stella devportal verify`) per DVOFF-64-002 and document operator workflows under `docs/airgap/devportal-offline.md`.
+- Expand `stella devportal verify` (DVOFF-64-002) to validate DSSE signatures and bundle integrity offline.
+- Document operator workflow under `docs/airgap/devportal-offline.md`.
diff --git a/docs/modules/orchestrator/README.md b/docs/modules/orchestrator/README.md
index be81fb099..151611da0 100644
--- a/docs/modules/orchestrator/README.md
+++ b/docs/modules/orchestrator/README.md
@@ -1,12 +1,15 @@
# StellaOps Source & Job Orchestrator
-The Orchestrator schedules, observes, and recovers ingestion and analysis jobs across the StellaOps platform.
-
-## Responsibilities
-- Track job state, throughput, and errors for Concelier, Excititor, Scheduler, and export pipelines.
-- Expose dashboards and APIs for throttling, replays, and failover.
-- Enforce rate-limits, concurrency and dependency chains across queues.
-- Stream structured events and audit logs for incident response.
+The Orchestrator schedules, observes, and recovers ingestion and analysis jobs across the StellaOps platform.
+
+## Latest updates (2025-11-01)
+- Authority added `orch:quota` and `orch:backfill` scopes for quota/backfill operations, plus token reason/ticket auditing (`docs/updates/2025-11-01-orch-admin-scope.md`). Operators must supply `quota_reason` / `quota_ticket` (or `backfill_reason` / `backfill_ticket`) when requesting elevated tokens and surface those claims in change reviews.
+
+## Responsibilities
+- Track job state, throughput, and errors for Concelier, Excititor, Scheduler, and export pipelines.
+- Expose dashboards and APIs for throttling, replays, and failover.
+- Enforce rate-limits, concurrency and dependency chains across queues.
+- Stream structured events and audit logs for incident response.
## Key components
- Orchestrator WebService (control plane).
@@ -19,10 +22,11 @@ The Orchestrator schedules, observes, and recovers ingestion and analysis jobs a
- Scheduler/Concelier/Excititor workers for job lifecycle.
- Offline Kit for state export/import during air-gap refreshes.
-## Operational notes
-- Job recovery runbooks and dashboard JSON as described in Epic 9.
-- Audit retention policies for job history.
-- Rate-limit reconfiguration guidelines.
+## Operational notes
+- Job recovery runbooks and dashboard JSON as described in Epic 9.
+- Audit retention policies for job history.
+- Rate-limit reconfiguration guidelines.
+- When using the new `orch:quota` / `orch:backfill` scopes, ensure reason/ticket fields are captured in runbooks and audit checklists per the 2025-11-01 Authority update.
## Epic alignment
- Epic 9: Source & Job Orchestrator Dashboard.
diff --git a/docs/modules/orchestrator/TASKS.md b/docs/modules/orchestrator/TASKS.md
index de6e1aefc..eae608a91 100644
--- a/docs/modules/orchestrator/TASKS.md
+++ b/docs/modules/orchestrator/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| SOURCE---JOB-ORCHESTRATOR-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Ensure ./README.md reflects the latest epic deliverables. | Align with ./AGENTS.md |
+| SOURCE---JOB-ORCHESTRATOR-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Ensure ./README.md reflects the latest epic deliverables. | README now calls out the 2025-11-01 Authority quota/backfill scope update and required audit metadata. |
| SOURCE---JOB-ORCHESTRATOR-ENG-0001 | TODO | Module Team | Break down epic milestones into actionable stories. | Sync into ../../TASKS.md |
| SOURCE---JOB-ORCHESTRATOR-OPS-0001 | TODO | Ops Guild | Prepare runbooks/observability assets once MVP lands. | Document outputs in ./README.md |
diff --git a/docs/modules/scanner/README.md b/docs/modules/scanner/README.md
index 8c4236cea..c08fb5ae9 100644
--- a/docs/modules/scanner/README.md
+++ b/docs/modules/scanner/README.md
@@ -2,6 +2,10 @@
Scanner analyses container images layer-by-layer, producing deterministic SBOM fragments, diffs, and signed reports.
+## Latest updates (2025-11-06)
+- Worker/WebService now resolve cache roots and feature flags via `StellaOps.Scanner.Surface.Env`; misconfiguration warnings are documented in `docs/modules/scanner/design/surface-env.md` and surfaced through startup validation.
+- Platform events rollout (2025-10-19) continues to publish scanner.report.ready@1 and scanner.scan.completed@1 envelopes with embedded DSSE payloads (see docs/updates/2025-10-19-scanner-policy.md and docs/updates/2025-10-19-platform-events.md). Service and consumer tests should round-trip the canonical samples under docs/events/samples/.
+
## Responsibilities
- Expose APIs (WebService) for scan orchestration, diffing, and artifact retrieval.
- Run Worker analyzers for OS, language, and native ecosystems with restart-only plug-ins.
diff --git a/docs/modules/scanner/TASKS.md b/docs/modules/scanner/TASKS.md
index 9cda2f75c..0e6981067 100644
--- a/docs/modules/scanner/TASKS.md
+++ b/docs/modules/scanner/TASKS.md
@@ -4,7 +4,7 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| SCANNER-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| SCANNER-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now highlights the 2025-10-19 platform-events rollout (scanner.report.ready@1 / scanner.scan.completed@1 DSSE envelopes). |
| SCANNER-DOCS-0002 | DONE (2025-11-02) | Docs Guild | Keep scanner benchmark comparisons (Trivy/Grype/Snyk) and deep-dive matrix current with source references. | Coordinate with docs/benchmarks owners |
| SCANNER-DOCS-0003 | TODO | Docs Guild, Product Guild | Gather Windows/macOS analyzer demand signals and record findings in `docs/benchmarks/scanner/windows-macos-demand.md`. | Coordinate with Product Marketing & Sales enablement |
| SCANNER-ENG-0008 | TODO | EntryTrace Guild, QA Guild | Maintain EntryTrace heuristic cadence per `docs/benchmarks/scanner/scanning-gaps-stella-misses-from-competitors.md`. | Include quarterly pattern review + explain trace updates |
diff --git a/docs/modules/scanner/design/surface-env.md b/docs/modules/scanner/design/surface-env.md
index 747d8df0f..9ce607cf2 100644
--- a/docs/modules/scanner/design/surface-env.md
+++ b/docs/modules/scanner/design/surface-env.md
@@ -115,6 +115,17 @@ Failures throw `SurfaceEnvironmentException` with error codes (`SURFACE_ENV_MISS
- **Scanner WebService**: build environment during startup using `AddSurfaceEnvironment`, `AddSurfaceValidation`, `AddSurfaceFileCache`, and `AddSurfaceSecrets`; readiness checks execute the validator runner and scan/report APIs emit Surface CAS pointers derived from the resolved configuration.
- **Zastava Observer/Webhook**: use the same builder; ensure Helm charts set `ZASTAVA_` variables.
- **Scheduler Planner (future)**: treat Surface.Env as read-only input; do not mutate settings.
+- `Scanner.Worker` and `Scanner.WebService` automatically bind the `SurfaceCacheOptions.RootDirectory` to `SurfaceEnvironment.Settings.CacheRoot` (2025-11-05); both hosts emit structured warnings (`surface.env.misconfiguration`) when the helper detects missing cache roots, endpoints, or secrets provider settings (2025-11-06).
+
+### 6.1 Misconfiguration warnings
+
+Surface.Env surfaces actionable warnings that appear in structured logs and readiness responses:
+
+- `surface.env.cache_root_missing` – emitted when the resolved cache directory does not exist or is not writable. The host attempts to create the directory once; subsequent failures block startup.
+- `surface.env.endpoint_unreachable` – emitted when `SurfaceFsEndpoint` is missing or not an absolute HTTPS URI.
+- `surface.env.secrets_provider_invalid` – emitted when the configured secrets provider lacks mandatory fields (e.g., `SCANNER_SURFACE_SECRETS_ROOT` for the `file` provider).
+
+Each warning includes remediation text and a reference to this design document; operations runbooks should treat these warnings as blockers in production and as validation hints in staging.
## 7. Security & Observability
diff --git a/docs/modules/signer/README.md b/docs/modules/signer/README.md
index b711069c5..7f092af48 100644
--- a/docs/modules/signer/README.md
+++ b/docs/modules/signer/README.md
@@ -1,21 +1,32 @@
# StellaOps Signer
-Signer validates callers, enforces Proof-of-Entitlement, and produces signed DSSE bundles for SBOMs, reports, and exports.
+Signer validates callers, enforces Proof-of-Entitlement, and produces signed DSSE bundles for SBOMs, reports, and exports.
+
+## Latest updates (Sprint 11 · 2025-10-21)
+- `/sign/dsse` pipeline landed with Authority OpTok + PoE enforcement, Fulcio/KMS signing modes, and deterministic DSSE bundles ready for Attestor logging.
+- `/verify/referrers` endpoint exposes release-integrity checks against scanner OCI referrers so callers can confirm digests before requesting signatures.
+- Plan quota enforcement (QPS/concurrency/artifact size) and audit/metrics wiring now align with the Sprint 11 signing-chain release.
-## Responsibilities
-- Enforce plan quotas and PoE before signing artifacts.
-- Support keyless and keyful signing backends.
-- Emit DSSE payloads consumed by Attestor and downstream bundles.
-- Maintain audit trails for all signing operations.
+## Responsibilities
+- Enforce Proof-of-Entitlement and plan quotas before signing artifacts.
+- Support keyless (Fulcio) and keyful (KMS/HSM) signing backends.
+- Verify scanner release integrity via OCI referrers prior to issuing signatures.
+- Emit DSSE payloads consumed by Attestor/Export Center and maintain comprehensive audit trails.
## Key components
- `StellaOps.Signer` service host.
- Crypto providers under `StellaOps.Cryptography.*`.
-## Integrations & dependencies
-- Authority for OpTok validation.
-- Attestor for transparency logging.
-- Export Center and CLI for artifact signing flows.
+## Integrations & dependencies
+- Authority for OpTok + PoE validation.
+- Licensing Service for entitlement introspection.
+- OCI registries (Referrers API) for scanner release verification.
+- Attestor for transparency logging and Rekor ingestion.
+- Export Center and CLI for artifact signing flows.
+
+## API quick reference
+- `POST /api/v1/signer/sign/dsse` — validate OpTok/PoE, enforce quotas, return DSSE bundle with signing identity metadata.
+- `GET /api/v1/signer/verify/referrers` — report scanner release signer and trust verdict for a supplied image digest.
## Operational notes
- Key management via Authority/DevOps runbooks.
diff --git a/docs/modules/signer/TASKS.md b/docs/modules/signer/TASKS.md
index ffbad4365..4695c9d25 100644
--- a/docs/modules/signer/TASKS.md
+++ b/docs/modules/signer/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| SIGNER-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| SIGNER-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now highlights Sprint 11 signing-chain release (sign/dsse, verify/referrers, quota enforcement). |
| SIGNER-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| SIGNER-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/telemetry/README.md b/docs/modules/telemetry/README.md
index 4cb8bd25b..04adca8d3 100644
--- a/docs/modules/telemetry/README.md
+++ b/docs/modules/telemetry/README.md
@@ -18,9 +18,10 @@ Telemetry module captures deployment and operations guidance for the shared obse
- Module-specific dashboards (scheduler, scanner, etc.).
- Security/Compliance for retention policies.
-## Operational notes
-- Smoke script references (../../ops/devops/telemetry).
-- Bundle packaging instructions in ops/devops/telemetry.
+## Operational notes
+- Smoke script references (../../ops/devops/telemetry).
+- Bundle packaging instructions in ops/devops/telemetry.
+- Sprint 23 console security sign-off (2025-10-27) added the `console-security.json` Grafana board and burn-rate alert pack—ensure environments import the updated dashboards/alerts referenced in `docs/updates/2025-10-27-console-security-signoff.md`.
## Related resources
- ./operations/collector.md
diff --git a/docs/modules/telemetry/TASKS.md b/docs/modules/telemetry/TASKS.md
index 243fe7d4f..6873a13ca 100644
--- a/docs/modules/telemetry/TASKS.md
+++ b/docs/modules/telemetry/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| TELEMETRY-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | See ./AGENTS.md |
+| TELEMETRY-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Validate that ./README.md aligns with the latest release notes. | README now captures the 2025-10-27 console security alert pack (console-security.json, burn-rate alert). |
| TELEMETRY-OPS-0001 | TODO | Ops Guild | Review runbooks/observability assets after next sprint demo. | Sync outcomes back to ../../TASKS.md |
| TELEMETRY-ENG-0001 | TODO | Module Team | Cross-check implementation plan milestones against `/docs/implplan/SPRINT_*.md`. | Update status via ./AGENTS.md workflow |
diff --git a/docs/modules/vuln-explorer/README.md b/docs/modules/vuln-explorer/README.md
index 37b45576a..79e59ba3a 100644
--- a/docs/modules/vuln-explorer/README.md
+++ b/docs/modules/vuln-explorer/README.md
@@ -1,11 +1,14 @@
# StellaOps Vulnerability Explorer
-Vulnerability Explorer delivers policy-aware triage, investigation, and reporting surfaces for effective findings.
-
-## Responsibilities
-- Present policy-evaluated findings with advisory, VEX, SBOM, and runtime context.
-- Capture triage workflow in an immutable findings ledger with role-based access.
-- Provide pivots, exports, and reports for auditors and operations teams.
+Vulnerability Explorer delivers policy-aware triage, investigation, and reporting surfaces for effective findings.
+
+## Latest updates (2025-11-03)
+- Access controls refresh introduced attachment signing tokens and updated scope guidance (`docs/updates/2025-11-03-vuln-explorer-access-controls.md`). Ensure operator runbooks reference the new Authority scopes (`authority-scopes.md`) and security checklist before enabling attachment uploads.
+
+## Responsibilities
+- Present policy-evaluated findings with advisory, VEX, SBOM, and runtime context.
+- Capture triage workflow in an immutable findings ledger with role-based access.
+- Provide pivots, exports, and reports for auditors and operations teams.
- Integrate explain traces, remediation notes, and offline bundles.
## Key components
diff --git a/docs/modules/vuln-explorer/TASKS.md b/docs/modules/vuln-explorer/TASKS.md
index 173f17d2b..1fd56326c 100644
--- a/docs/modules/vuln-explorer/TASKS.md
+++ b/docs/modules/vuln-explorer/TASKS.md
@@ -4,6 +4,6 @@
| ID | Status | Owner(s) | Description | Notes |
|----|--------|----------|-------------|-------|
-| VULNERABILITY-EXPLORER-DOCS-0001 | DOING (2025-10-29) | Docs Guild | Ensure ./README.md reflects the latest epic deliverables. | Align with ./AGENTS.md |
+| VULNERABILITY-EXPLORER-DOCS-0001 | DONE (2025-11-05) | Docs Guild | Ensure ./README.md reflects the latest epic deliverables. | README now includes the 2025-11-03 access-control refresh (attachment signing tokens & scope guidance). |
| VULNERABILITY-EXPLORER-ENG-0001 | TODO | Module Team | Break down epic milestones into actionable stories. | Sync into ../../TASKS.md |
| VULNERABILITY-EXPLORER-OPS-0001 | TODO | Ops Guild | Prepare runbooks/observability assets once MVP lands. | Document outputs in ./README.md |
diff --git a/docs/updates/2025-11-05-excitor-consensus-beta.md b/docs/updates/2025-11-05-excitor-consensus-beta.md
new file mode 100644
index 000000000..52d5b4f2a
--- /dev/null
+++ b/docs/updates/2025-11-05-excitor-consensus-beta.md
@@ -0,0 +1,12 @@
+# 2025-11-05 – Excitor consensus API beta
+
+**Subject:** Excitor consensus export/API preview ships \
+**Audience:** Docs Guild, VEX Lens Guild, Policy Engine Guild, Export Center Guild
+
+- Published `docs/modules/excitor/README.md` update capturing the Link-Not-Merge consensus milestone and pointing to the beta API surface.
+- Added `docs/vex/consensus-json.md` sample describing the canonical `consensus_state` payload (`rollupStatus`, `sources[]`, `policyRevisionId`, `consensusDigest`) emitted by the preview endpoint.
+- Documented DSSE packaging plus Export Center hooks so attested consensus bundles can ride along with devportal/offline exports once Excitor workers emit DSSE manifests (`docs/modules/export-center/devportal-offline.md`).
+
+**Follow-ups**
+- [ ] Coordinate with Policy Engine (`POLICY-ENGINE-30-101`) to reference consensus policy weighting knobs before GA.
+- [ ] Produce CLI quickstart once `stella vex consensus` verbs land (CLI backlog `CLI-VEX-30-002`).
diff --git a/docs/vex/consensus-json.md b/docs/vex/consensus-json.md
new file mode 100644
index 000000000..9ddafbb32
--- /dev/null
+++ b/docs/vex/consensus-json.md
@@ -0,0 +1,34 @@
+# Excitor consensus JSON sample (beta)
+
+```jsonc
+{
+ "vulnId": "CVE-2025-12345",
+ "productKey": "pkg:maven/org.apache.commons/commons-text@1.11.0",
+ "rollupStatus": "NOT_AFFECTED",
+ "sources": [
+ {
+ "providerId": "redhat",
+ "status": "NOT_AFFECTED",
+ "justification": "component_not_present",
+ "weight": 0.62,
+ "lastObserved": "2025-11-04T18:22:31Z",
+ "accepted": true,
+ "reason": "trust-tier vendor, signed OpenVEX"
+ },
+ {
+ "providerId": "github",
+ "status": "AFFECTED",
+ "justification": null,
+ "weight": 0.27,
+ "lastObserved": "2025-11-05T01:12:03Z",
+ "accepted": false,
+ "reason": "lower trust tier and stale statement"
+ }
+ ],
+ "policyRevisionId": "vex-consensus-policy@2025-11-05",
+ "evaluatedAt": "2025-11-05T02:05:14Z",
+ "consensusDigest": "sha256:41f2d96728b24f7a8b7f1251983b8edccd1e0f5781d4a51e51c8e6b20c1fa31a"
+}
+```
+
+> **Note:** This payload is generated from the beta consensus endpoint and is subject to change prior to GA. Keys and semantics are documented alongside API previews in `docs/modules/excitor/README.md`.
diff --git a/local-nuget/Google.Api.Gax.Grpc.4.7.0.nupkg b/local-nuget/Google.Api.Gax.Grpc.4.7.0.nupkg
new file mode 100644
index 000000000..a531abd0e
Binary files /dev/null and b/local-nuget/Google.Api.Gax.Grpc.4.7.0.nupkg differ
diff --git a/local-nuget/Google.Apis.Core.1.64.0.nupkg b/local-nuget/Google.Apis.Core.1.64.0.nupkg
new file mode 100644
index 000000000..b8b1e8be4
Binary files /dev/null and b/local-nuget/Google.Apis.Core.1.64.0.nupkg differ
diff --git a/local-nuget/Google.Cloud.Kms.V1.3.19.0.nupkg b/local-nuget/Google.Cloud.Kms.V1.3.19.0.nupkg
new file mode 100644
index 000000000..7d5fcf1aa
Binary files /dev/null and b/local-nuget/Google.Cloud.Kms.V1.3.19.0.nupkg differ
diff --git a/local-nuget/Google.Protobuf.3.31.1.nupkg b/local-nuget/Google.Protobuf.3.31.1.nupkg
new file mode 100644
index 000000000..cba650326
Binary files /dev/null and b/local-nuget/Google.Protobuf.3.31.1.nupkg differ
diff --git a/local-nuget/Grpc.Auth.2.71.0.nupkg b/local-nuget/Grpc.Auth.2.71.0.nupkg
new file mode 100644
index 000000000..2773616bc
Binary files /dev/null and b/local-nuget/Grpc.Auth.2.71.0.nupkg differ
diff --git a/local-nuget/Grpc.Core.Api.2.71.0.nupkg b/local-nuget/Grpc.Core.Api.2.71.0.nupkg
new file mode 100644
index 000000000..32dba3f32
Binary files /dev/null and b/local-nuget/Grpc.Core.Api.2.71.0.nupkg differ
diff --git a/local-nuget/Grpc.Net.Client.2.71.0.nupkg b/local-nuget/Grpc.Net.Client.2.71.0.nupkg
new file mode 100644
index 000000000..071cfb626
Binary files /dev/null and b/local-nuget/Grpc.Net.Client.2.71.0.nupkg differ
diff --git a/local-nuget/Grpc.Net.Common.2.71.0.nupkg b/local-nuget/Grpc.Net.Common.2.71.0.nupkg
new file mode 100644
index 000000000..219045bba
Binary files /dev/null and b/local-nuget/Grpc.Net.Common.2.71.0.nupkg differ
diff --git a/local-nuget/Grpc.Tools.2.71.0.nupkg b/local-nuget/Grpc.Tools.2.71.0.nupkg
new file mode 100644
index 000000000..3de683b30
Binary files /dev/null and b/local-nuget/Grpc.Tools.2.71.0.nupkg differ
diff --git a/local-nuget/Pkcs11Interop.5.3.0.nupkg b/local-nuget/Pkcs11Interop.5.3.0.nupkg
new file mode 100644
index 000000000..754865202
Binary files /dev/null and b/local-nuget/Pkcs11Interop.5.3.0.nupkg differ
diff --git a/ops/devops/TASKS.md b/ops/devops/TASKS.md
index 7978b9d24..e079a06e4 100644
--- a/ops/devops/TASKS.md
+++ b/ops/devops/TASKS.md
@@ -13,6 +13,9 @@
> Docs hand-off (2025-10-26): see `docs/ingestion/aggregation-only-contract.md` §5, `docs/modules/platform/architecture-overview.md`, and `docs/modules/cli/guides/cli-reference.md` for guard + verifier expectations.
| DEVOPS-AOC-19-002 | BLOCKED (2025-10-26) | DevOps Guild | CLI-AOC-19-002, CONCELIER-WEB-AOC-19-004, EXCITITOR-WEB-AOC-19-004 | Add pipeline stage executing `stella aoc verify --since` against seeded Mongo snapshots for Concelier + Excititor, publishing violation report artefacts. | Stage runs on main/nightly, fails on violations, artifacts retained, runbook documented. |
> Blocked: waiting on CLI verifier command and Concelier/Excititor guard endpoints to land (CLI-AOC-19-002, CONCELIER-WEB-AOC-19-004, EXCITITOR-WEB-AOC-19-004).
+| DEVOPS-OPENSSL-11-001 | TODO (2025-11-06) | DevOps Guild, Build Infra Guild | — | Package the OpenSSL 1.1 shim (`tests/native/openssl-1.1/linux-x64`) into test harness output so Mongo2Go suites discover it automatically. | Shim copied during `dotnet test`, documentation updated, redundant manual extraction removed. |
+> 2025-11-06: Interim guidance published in `tests/native/openssl-1.1/README.md` and `deploy/README.md`; automation still required.
+| DEVOPS-OPENSSL-11-002 | TODO (2025-11-06) | DevOps Guild, CI Guild | DEVOPS-OPENSSL-11-001 | Ensure CI runners and Docker images that execute Mongo2Go tests export `LD_LIBRARY_PATH` (or embed the shim) to unblock unattended pipelines. | CI jobs set the variable or bake the libraries; runbook documents the location; smoke builds green without manual exports. |
| DEVOPS-AOC-19-003 | BLOCKED (2025-10-26) | DevOps Guild, QA Guild | CONCELIER-WEB-AOC-19-003, EXCITITOR-WEB-AOC-19-003 | Enforce unit test coverage thresholds for AOC guard suites and ensure coverage exported to dashboards. | Coverage report includes guard projects, threshold gate passes/fails as expected, dashboards refreshed with new metrics. |
> Blocked: guard coverage suites and exporter hooks pending in Concelier/Excititor (CONCELIER-WEB-AOC-19-003, EXCITITOR-WEB-AOC-19-003).
| DEVOPS-AOC-19-101 | TODO (2025-10-28) | DevOps Guild, Concelier Storage Guild | CONCELIER-STORE-AOC-19-002 | Draft supersedes backfill rollout (freeze window, dry-run steps, rollback) once advisory_raw idempotency index passes staging verification. | Runbook committed in `docs/deploy/containers.md` + Offline Kit notes, staging rehearsal scheduled with dependencies captured in SPRINTS. |
diff --git a/src/Cli/StellaOps.Cli/Commands/CommandFactory.cs b/src/Cli/StellaOps.Cli/Commands/CommandFactory.cs
index dfe085ad6..da07f8d7e 100644
--- a/src/Cli/StellaOps.Cli/Commands/CommandFactory.cs
+++ b/src/Cli/StellaOps.Cli/Commands/CommandFactory.cs
@@ -730,10 +730,11 @@ internal static class CommandFactory
};
activate.Add(activatePolicyIdArgument);
- var activateVersionOption = new Option("--version")
- {
- Description = "Revision version to activate."
- };
+ var activateVersionOption = new Option("--version")
+ {
+ Description = "Revision version to activate.",
+ IsRequired = true
+ };
var activationNoteOption = new Option("--note")
{
diff --git a/src/Cli/StellaOps.Cli/TASKS.md b/src/Cli/StellaOps.Cli/TASKS.md
index 1f0ff5215..3ccb8553b 100644
--- a/src/Cli/StellaOps.Cli/TASKS.md
+++ b/src/Cli/StellaOps.Cli/TASKS.md
@@ -49,6 +49,7 @@
| CLI-POLICY-23-004 | TODO | DevEx/CLI Guild | WEB-POLICY-23-001 | Add `stella policy lint` command validating SPL files with compiler diagnostics; support JSON output. | Command returns lint diagnostics; exit codes documented; tests cover error scenarios. |
| CLI-POLICY-23-005 | DOING (2025-10-28) | DevEx/CLI Guild | POLICY-GATEWAY-18-002..003, WEB-POLICY-23-002 | Implement `stella policy activate` with scheduling window, approval enforcement, and summary output. | Activation command integrates with API, handles 2-person rule failures; tests cover success/error. |
> 2025-10-28: CLI command implemented with gateway integration (`policy activate`), interactive summary output, retry-aware metrics, and exit codes (0 success, 75 pending second approval). Tests cover success/pending/error paths.
+> 2025-11-06: Tightened required `--version` parsing, added scheduled activation handling coverage, and expanded tests to validate timestamp normalization.
| CLI-POLICY-23-006 | TODO | DevEx/CLI Guild | WEB-POLICY-23-004 | Provide `stella policy history` and `stella policy explain` commands to pull run history and explanation trees. | Commands output JSON/table; integration tests with fixtures; docs updated. |
## Graph & Vuln Explorer v1
diff --git a/src/Cli/__Tests/StellaOps.Cli.Tests/Commands/CommandHandlersTests.cs b/src/Cli/__Tests/StellaOps.Cli.Tests/Commands/CommandHandlersTests.cs
index d770940a5..20ab1b4d4 100644
--- a/src/Cli/__Tests/StellaOps.Cli.Tests/Commands/CommandHandlersTests.cs
+++ b/src/Cli/__Tests/StellaOps.Cli.Tests/Commands/CommandHandlersTests.cs
@@ -1811,11 +1811,11 @@ spec:
}
[Fact]
- public async Task HandlePolicyActivateAsync_PendingSecondApprovalSetsExitCode()
- {
- var originalExit = Environment.ExitCode;
-
- var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null));
+ public async Task HandlePolicyActivateAsync_PendingSecondApprovalSetsExitCode()
+ {
+ var originalExit = Environment.ExitCode;
+
+ var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null));
backend.ActivationResult = new PolicyActivationResult(
"pending_second_approval",
new PolicyActivationRevision(
@@ -1852,15 +1852,65 @@ spec:
finally
{
Environment.ExitCode = originalExit;
- }
- }
-
- [Fact]
- public async Task HandlePolicyActivateAsync_MapsErrorCodes()
- {
- var originalExit = Environment.ExitCode;
-
- var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null))
+ }
+ }
+
+ [Fact]
+ public async Task HandlePolicyActivateAsync_ParsesScheduledTimestamp()
+ {
+ var originalExit = Environment.ExitCode;
+ var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null));
+ backend.ActivationResult = new PolicyActivationResult(
+ "scheduled",
+ new PolicyActivationRevision(
+ "P-8",
+ 5,
+ "approved",
+ false,
+ DateTimeOffset.Parse("2025-12-01T00:30:00Z", CultureInfo.InvariantCulture),
+ null,
+ new ReadOnlyCollection(Array.Empty())));
+
+ var provider = BuildServiceProvider(backend);
+
+ try
+ {
+ const string scheduledValue = "2025-12-01T03:00:00+02:00";
+ await CommandHandlers.HandlePolicyActivateAsync(
+ provider,
+ policyId: "P-8",
+ version: 5,
+ note: null,
+ runNow: false,
+ scheduledAt: scheduledValue,
+ priority: null,
+ rollback: false,
+ incidentId: null,
+ verbose: false,
+ cancellationToken: CancellationToken.None);
+
+ Assert.Equal(0, Environment.ExitCode);
+ Assert.NotNull(backend.LastPolicyActivation);
+ var activation = backend.LastPolicyActivation!.Value;
+ Assert.False(activation.Request.RunNow);
+ var expected = DateTimeOffset.Parse(
+ scheduledValue,
+ CultureInfo.InvariantCulture,
+ DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal);
+ Assert.Equal(expected, activation.Request.ScheduledAt);
+ }
+ finally
+ {
+ Environment.ExitCode = originalExit;
+ }
+ }
+
+ [Fact]
+ public async Task HandlePolicyActivateAsync_MapsErrorCodes()
+ {
+ var originalExit = Environment.ExitCode;
+
+ var backend = new StubBackendClient(new JobTriggerResult(true, "ok", null, null))
{
ActivationException = new PolicyApiException("Revision not approved", HttpStatusCode.BadRequest, "ERR_POL_002")
};
diff --git a/src/Concelier/StellaOps.Concelier.WebService/Extensions/JobRegistrationExtensions.cs b/src/Concelier/StellaOps.Concelier.WebService/Extensions/JobRegistrationExtensions.cs
index 91b574ed8..271e152d8 100644
--- a/src/Concelier/StellaOps.Concelier.WebService/Extensions/JobRegistrationExtensions.cs
+++ b/src/Concelier/StellaOps.Concelier.WebService/Extensions/JobRegistrationExtensions.cs
@@ -52,9 +52,11 @@ internal static class JobRegistrationExtensions
new("source:vndr-oracle:parse", "StellaOps.Concelier.Connector.Vndr.Oracle.OracleParseJob", "StellaOps.Concelier.Connector.Vndr.Oracle", TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(5)),
new("source:vndr-oracle:map", "StellaOps.Concelier.Connector.Vndr.Oracle.OracleMapJob", "StellaOps.Concelier.Connector.Vndr.Oracle", TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(5)),
- new("export:json", "StellaOps.Concelier.Exporter.Json.JsonExportJob", "StellaOps.Concelier.Exporter.Json", TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(5)),
+ new("export:json", "StellaOps.Concelier.Exporter.Json.JsonExportJob", "StellaOps.Concelier.Exporter.Json", TimeSpan.FromMinutes(10), TimeSpan.FromMinutes(5)),
new("export:trivy-db", "StellaOps.Concelier.Exporter.TrivyDb.TrivyDbExportJob", "StellaOps.Concelier.Exporter.TrivyDb", TimeSpan.FromMinutes(20), TimeSpan.FromMinutes(10)),
+#pragma warning disable CS0618, CONCELIER0001 // Legacy merge job remains available until MERGE-LNM-21-002 completes.
new("merge:reconcile", "StellaOps.Concelier.Merge.Jobs.MergeReconcileJob", "StellaOps.Concelier.Merge", TimeSpan.FromMinutes(15), TimeSpan.FromMinutes(5))
+#pragma warning restore CS0618, CONCELIER0001
};
public static IServiceCollection AddBuiltInConcelierJobs(this IServiceCollection services)
diff --git a/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptions.cs b/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptions.cs
index 3caec1558..d964b5503 100644
--- a/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptions.cs
+++ b/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptions.cs
@@ -15,6 +15,8 @@ public sealed class ConcelierOptions
public AuthorityOptions Authority { get; set; } = new();
public MirrorOptions Mirror { get; set; } = new();
+
+ public FeaturesOptions Features { get; set; } = new();
public sealed class StorageOptions
{
@@ -135,4 +137,13 @@ public sealed class ConcelierOptions
public int MaxDownloadRequestsPerHour { get; set; } = 1200;
}
+
+ public sealed class FeaturesOptions
+ {
+ public bool NoMergeEnabled { get; set; }
+
+ public bool LnmShadowWrites { get; set; } = true;
+
+ public IList MergeJobAllowlist { get; } = new List();
+ }
}
diff --git a/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptionsPostConfigure.cs b/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptionsPostConfigure.cs
index 1774df313..c87bbf911 100644
--- a/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptionsPostConfigure.cs
+++ b/src/Concelier/StellaOps.Concelier.WebService/Options/ConcelierOptionsPostConfigure.cs
@@ -17,7 +17,8 @@ public static class ConcelierOptionsPostConfigure
{
ArgumentNullException.ThrowIfNull(options);
- options.Authority ??= new ConcelierOptions.AuthorityOptions();
+ options.Authority ??= new ConcelierOptions.AuthorityOptions();
+ options.Features ??= new ConcelierOptions.FeaturesOptions();
var authority = options.Authority;
if (string.IsNullOrWhiteSpace(authority.ClientSecret)
diff --git a/src/Concelier/StellaOps.Concelier.WebService/Program.cs b/src/Concelier/StellaOps.Concelier.WebService/Program.cs
index 5374ce3ea..68f94a12d 100644
--- a/src/Concelier/StellaOps.Concelier.WebService/Program.cs
+++ b/src/Concelier/StellaOps.Concelier.WebService/Program.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Globalization;
@@ -98,9 +99,36 @@ builder.Services.AddConcelierLinksetMappers();
builder.Services.AddAdvisoryRawServices();
builder.Services.AddSingleton();
-builder.Services.AddMergeModule(builder.Configuration);
+var features = concelierOptions.Features ?? new ConcelierOptions.FeaturesOptions();
+
+if (!features.NoMergeEnabled)
+{
+#pragma warning disable CS0618, CONCELIER0001, CONCELIER0002 // Legacy merge service is intentionally supported behind a feature toggle.
+ builder.Services.AddMergeModule(builder.Configuration);
+#pragma warning restore CS0618, CONCELIER0001, CONCELIER0002
+}
+
builder.Services.AddJobScheduler();
builder.Services.AddBuiltInConcelierJobs();
+builder.Services.PostConfigure(options =>
+{
+ if (features.NoMergeEnabled)
+ {
+ options.Definitions.Remove("merge:reconcile");
+ return;
+ }
+
+ if (features.MergeJobAllowlist is { Count: > 0 })
+ {
+ var allowMergeJob = features.MergeJobAllowlist.Any(value =>
+ string.Equals(value, "merge:reconcile", StringComparison.OrdinalIgnoreCase));
+
+ if (!allowMergeJob)
+ {
+ options.Definitions.Remove("merge:reconcile");
+ }
+ }
+});
builder.Services.AddSingleton();
builder.Services.AddSingleton(sp => new ServiceStatus(sp.GetRequiredService()));
@@ -183,7 +211,7 @@ if (authorityConfigured)
builder.Services.AddAuthorization(options =>
{
options.AddStellaOpsScopePolicy(JobsPolicyName, concelierOptions.Authority.RequiredScopes.ToArray());
- options.AddStellaOpsScopePolicy(ObservationsPolicyName, StellaOpsScopes.VulnRead);
+ options.AddStellaOpsScopePolicy(ObservationsPolicyName, StellaOpsScopes.VulnView);
options.AddStellaOpsScopePolicy(AdvisoryIngestPolicyName, StellaOpsScopes.AdvisoryIngest);
options.AddStellaOpsScopePolicy(AdvisoryReadPolicyName, StellaOpsScopes.AdvisoryRead);
options.AddStellaOpsScopePolicy(AocVerifyPolicyName, StellaOpsScopes.AdvisoryRead, StellaOpsScopes.AocVerify);
@@ -197,6 +225,11 @@ builder.Services.AddEndpointsApiExplorer();
var app = builder.Build();
+if (features.NoMergeEnabled)
+{
+ app.Logger.LogWarning("Legacy merge module disabled via concelier:features:noMergeEnabled; Link-Not-Merge mode active.");
+}
+
var resolvedConcelierOptions = app.Services.GetRequiredService>().Value;
var resolvedAuthority = resolvedConcelierOptions.Authority ?? new ConcelierOptions.AuthorityOptions();
authorityConfigured = resolvedAuthority.Enabled;
diff --git a/src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj b/src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj
index d2d1b0d3f..9fc94d0d7 100644
--- a/src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj
+++ b/src/Concelier/StellaOps.Concelier.WebService/StellaOps.Concelier.WebService.csproj
@@ -35,5 +35,8 @@
+
diff --git a/src/Concelier/StellaOps.Concelier.sln b/src/Concelier/StellaOps.Concelier.sln
index 6316129c9..3f126d545 100644
--- a/src/Concelier/StellaOps.Concelier.sln
+++ b/src/Concelier/StellaOps.Concelier.sln
@@ -1,1336 +1,1353 @@
-
-Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio Version 17
-VisualStudioVersion = 17.0.31903.59
-MinimumVisualStudioVersion = 10.0.40219.1
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.WebService", "StellaOps.Concelier.WebService\StellaOps.Concelier.WebService.csproj", "{FB98E71B-AF9D-4593-8306-F989C2CA2BBE}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Libraries", "__Libraries", "{41F15E67-7190-CF23-3BC4-77E87134CADD}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Core", "__Libraries\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj", "{D93F34C2-5E5E-4CC7-A573-4376AA525838}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Models", "__Libraries\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj", "{841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.RawModels", "__Libraries\StellaOps.Concelier.RawModels\StellaOps.Concelier.RawModels.csproj", "{EEC52FA0-8E78-4FCB-9454-D697F58B2118}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Normalization", "__Libraries\StellaOps.Concelier.Normalization\StellaOps.Concelier.Normalization.csproj", "{628700D6-97A5-4506-BC78-22E2A76C68E3}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Plugin", "..\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj", "{A3E52755-5B68-4A33-9078-893A7FEE7D4B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.DependencyInjection", "..\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj", "{7B48F422-65E3-464B-B029-0766207035EB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Aoc", "..\Aoc\__Libraries\StellaOps.Aoc\StellaOps.Aoc.csproj", "{A6802486-A8D3-4623-8D81-04ED23F9D312}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Storage.Mongo", "__Libraries\StellaOps.Concelier.Storage.Mongo\StellaOps.Concelier.Storage.Mongo.csproj", "{C926373D-5ACB-4E62-96D5-264EF4C61BE5}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Common", "__Libraries\StellaOps.Concelier.Connector.Common\StellaOps.Concelier.Connector.Common.csproj", "{2D68125A-0ACD-4015-A8FA-B54284B8A3CB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Merge", "__Libraries\StellaOps.Concelier.Merge\StellaOps.Concelier.Merge.csproj", "{7760219F-6C19-4B61-9015-73BB02005C0B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Configuration", "..\__Libraries\StellaOps.Configuration\StellaOps.Configuration.csproj", "{EDD39EE5-8341-4BB0-9C30-D829D97C1E65}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Authority.Plugins.Abstractions", "..\Authority\StellaOps.Authority\StellaOps.Authority.Plugins.Abstractions\StellaOps.Authority.Plugins.Abstractions.csproj", "{80E7B08C-2916-4540-A34B-CB581EEEA202}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Cryptography", "..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj", "{5B04974C-EC04-446E-83C1-EF9686433586}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Auth.Abstractions", "..\Authority\StellaOps.Authority\StellaOps.Auth.Abstractions\StellaOps.Auth.Abstractions.csproj", "{1282AA12-C27D-4F85-B534-785FEFF52D5F}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Auth.Client", "..\Authority\StellaOps.Authority\StellaOps.Auth.Client\StellaOps.Auth.Client.csproj", "{C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Auth.ServerIntegration", "..\Authority\StellaOps.Authority\StellaOps.Auth.ServerIntegration\StellaOps.Auth.ServerIntegration.csproj", "{A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Acsc", "__Libraries\StellaOps.Concelier.Connector.Acsc\StellaOps.Concelier.Connector.Acsc.csproj", "{F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cccs", "__Libraries\StellaOps.Concelier.Connector.Cccs\StellaOps.Concelier.Connector.Cccs.csproj", "{30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertBund", "__Libraries\StellaOps.Concelier.Connector.CertBund\StellaOps.Concelier.Connector.CertBund.csproj", "{77FF9993-C811-4389-8BFE-974B4F0AB7C6}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertCc", "__Libraries\StellaOps.Concelier.Connector.CertCc\StellaOps.Concelier.Connector.CertCc.csproj", "{4FB18D5B-8D48-4E50-9608-69890B3420F8}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertFr", "__Libraries\StellaOps.Concelier.Connector.CertFr\StellaOps.Concelier.Connector.CertFr.csproj", "{585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertIn", "__Libraries\StellaOps.Concelier.Connector.CertIn\StellaOps.Concelier.Connector.CertIn.csproj", "{BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cve", "__Libraries\StellaOps.Concelier.Connector.Cve\StellaOps.Concelier.Connector.Cve.csproj", "{257E2D7B-EA3D-4B33-9546-7B77DA20A517}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Debian", "__Libraries\StellaOps.Concelier.Connector.Distro.Debian\StellaOps.Concelier.Connector.Distro.Debian.csproj", "{5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.RedHat", "__Libraries\StellaOps.Concelier.Connector.Distro.RedHat\StellaOps.Concelier.Connector.Distro.RedHat.csproj", "{C827F73E-68E2-4F6A-8CEA-0425B2D2D466}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Suse", "__Libraries\StellaOps.Concelier.Connector.Distro.Suse\StellaOps.Concelier.Connector.Distro.Suse.csproj", "{F67EECB0-7DCC-4643-82F3-E020D72BE762}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Ubuntu", "__Libraries\StellaOps.Concelier.Connector.Distro.Ubuntu\StellaOps.Concelier.Connector.Distro.Ubuntu.csproj", "{2975AE79-F23D-43D6-B075-6659AB6AE105}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ghsa", "__Libraries\StellaOps.Concelier.Connector.Ghsa\StellaOps.Concelier.Connector.Ghsa.csproj", "{667ACFE7-922E-4958-99D6-DD9D7BE8E744}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Cisa", "__Libraries\StellaOps.Concelier.Connector.Ics.Cisa\StellaOps.Concelier.Connector.Ics.Cisa.csproj", "{D4824290-3F8A-47BD-A368-F63BE593546B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Kaspersky", "__Libraries\StellaOps.Concelier.Connector.Ics.Kaspersky\StellaOps.Concelier.Connector.Ics.Kaspersky.csproj", "{B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Jvn", "__Libraries\StellaOps.Concelier.Connector.Jvn\StellaOps.Concelier.Connector.Jvn.csproj", "{33C98234-DF04-40CE-9459-2736AAB0CF6C}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kev", "__Libraries\StellaOps.Concelier.Connector.Kev\StellaOps.Concelier.Connector.Kev.csproj", "{A6D364F9-3478-4432-9EE1-F4F3DCF125EA}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kisa", "__Libraries\StellaOps.Concelier.Connector.Kisa\StellaOps.Concelier.Connector.Kisa.csproj", "{B9EDA23E-5754-48AF-8978-DBCBF75134BF}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Nvd", "__Libraries\StellaOps.Concelier.Connector.Nvd\StellaOps.Concelier.Connector.Nvd.csproj", "{9208F373-EDD1-491D-AEF9-FE280B453CD9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Osv", "__Libraries\StellaOps.Concelier.Connector.Osv\StellaOps.Concelier.Connector.Osv.csproj", "{EC5DE6F3-D158-4261-A4CD-AB81AE154918}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Bdu", "__Libraries\StellaOps.Concelier.Connector.Ru.Bdu\StellaOps.Concelier.Connector.Ru.Bdu.csproj", "{40591EC3-23C6-4E74-8280-35153641FF21}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Nkcki", "__Libraries\StellaOps.Concelier.Connector.Ru.Nkcki\StellaOps.Concelier.Connector.Ru.Nkcki.csproj", "{5646F7F2-FEDF-49D1-9053-F8E1B7892695}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.StellaOpsMirror", "__Libraries\StellaOps.Concelier.Connector.StellaOpsMirror\StellaOps.Concelier.Connector.StellaOpsMirror.csproj", "{3C877F0B-3870-452B-AA70-1F9960A4F062}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Adobe", "__Libraries\StellaOps.Concelier.Connector.Vndr.Adobe\StellaOps.Concelier.Connector.Vndr.Adobe.csproj", "{5525AD40-01DA-46DD-B331-DD032DD3C9C0}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Apple", "__Libraries\StellaOps.Concelier.Connector.Vndr.Apple\StellaOps.Concelier.Connector.Vndr.Apple.csproj", "{D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Chromium", "__Libraries\StellaOps.Concelier.Connector.Vndr.Chromium\StellaOps.Concelier.Connector.Vndr.Chromium.csproj", "{296A426A-E429-4984-8813-AA7EEE3037D5}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Cisco", "__Libraries\StellaOps.Concelier.Connector.Vndr.Cisco\StellaOps.Concelier.Connector.Vndr.Cisco.csproj", "{6F1AB15F-8875-4A62-A878-842D463A3B11}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Msrc", "__Libraries\StellaOps.Concelier.Connector.Vndr.Msrc\StellaOps.Concelier.Connector.Vndr.Msrc.csproj", "{CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Oracle", "__Libraries\StellaOps.Concelier.Connector.Vndr.Oracle\StellaOps.Concelier.Connector.Vndr.Oracle.csproj", "{8EFE438F-0513-470C-909B-8A1BD62D0E98}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Vmware", "__Libraries\StellaOps.Concelier.Connector.Vndr.Vmware\StellaOps.Concelier.Connector.Vndr.Vmware.csproj", "{60712A8D-FF22-452C-8AC0-22DB33B38180}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.Json", "__Libraries\StellaOps.Concelier.Exporter.Json\StellaOps.Concelier.Exporter.Json.csproj", "{4097C3CB-7C39-478B-89C2-4D317625EBBF}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.TrivyDb", "__Libraries\StellaOps.Concelier.Exporter.TrivyDb\StellaOps.Concelier.Exporter.TrivyDb.csproj", "{935D16AC-8EBD-46E4-8D0E-934F3AE961D4}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Testing", "__Libraries\StellaOps.Concelier.Testing\StellaOps.Concelier.Testing.csproj", "{0BC8276D-D726-4C8B-AB2B-122BE18F1112}"
-EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Tests", "__Tests", "{56BCE1BF-7CBA-7CE8-203D-A88051F1D642}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Acsc.Tests", "__Tests\StellaOps.Concelier.Connector.Acsc.Tests\StellaOps.Concelier.Connector.Acsc.Tests.csproj", "{654CF4EE-9EC5-464C-AF47-EE37329CD46A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cccs.Tests", "__Tests\StellaOps.Concelier.Connector.Cccs.Tests\StellaOps.Concelier.Connector.Cccs.Tests.csproj", "{BEF6FA33-E0EA-4ED2-B209-833D41607132}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertBund.Tests", "__Tests\StellaOps.Concelier.Connector.CertBund.Tests\StellaOps.Concelier.Connector.CertBund.Tests.csproj", "{B777945B-92DB-4D24-A795-5C900B6FCB92}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertCc.Tests", "__Tests\StellaOps.Concelier.Connector.CertCc.Tests\StellaOps.Concelier.Connector.CertCc.Tests.csproj", "{67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertFr.Tests", "__Tests\StellaOps.Concelier.Connector.CertFr.Tests\StellaOps.Concelier.Connector.CertFr.Tests.csproj", "{0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertIn.Tests", "__Tests\StellaOps.Concelier.Connector.CertIn.Tests\StellaOps.Concelier.Connector.CertIn.Tests.csproj", "{0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Common.Tests", "__Tests\StellaOps.Concelier.Connector.Common.Tests\StellaOps.Concelier.Connector.Common.Tests.csproj", "{35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cve.Tests", "__Tests\StellaOps.Concelier.Connector.Cve.Tests\StellaOps.Concelier.Connector.Cve.Tests.csproj", "{F90FCF19-0426-4E62-93DC-835712E5B064}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Debian.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.Debian.Tests\StellaOps.Concelier.Connector.Distro.Debian.Tests.csproj", "{0E84E05F-53CE-4A6E-95F0-62EF14CBC385}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.RedHat.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.RedHat.Tests\StellaOps.Concelier.Connector.Distro.RedHat.Tests.csproj", "{7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Suse.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.Suse.Tests\StellaOps.Concelier.Connector.Distro.Suse.Tests.csproj", "{4DD7C512-5624-4C6B-B02A-7EDF58242657}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Ubuntu.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.Ubuntu.Tests\StellaOps.Concelier.Connector.Distro.Ubuntu.Tests.csproj", "{98AA9471-2498-45BC-A58F-B83F4B9A8B75}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ghsa.Tests", "__Tests\StellaOps.Concelier.Connector.Ghsa.Tests\StellaOps.Concelier.Connector.Ghsa.Tests.csproj", "{7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Cisa.Tests", "__Tests\StellaOps.Concelier.Connector.Ics.Cisa.Tests\StellaOps.Concelier.Connector.Ics.Cisa.Tests.csproj", "{253BAF8F-0CF8-4D1A-B5AA-F19713099173}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Kaspersky.Tests", "__Tests\StellaOps.Concelier.Connector.Ics.Kaspersky.Tests\StellaOps.Concelier.Connector.Ics.Kaspersky.Tests.csproj", "{57A423CD-4F40-4BAD-A6FC-93D494FCA51A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Jvn.Tests", "__Tests\StellaOps.Concelier.Connector.Jvn.Tests\StellaOps.Concelier.Connector.Jvn.Tests.csproj", "{07034F70-3E4F-49BF-A181-75443D3B3361}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kev.Tests", "__Tests\StellaOps.Concelier.Connector.Kev.Tests\StellaOps.Concelier.Connector.Kev.Tests.csproj", "{E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kisa.Tests", "__Tests\StellaOps.Concelier.Connector.Kisa.Tests\StellaOps.Concelier.Connector.Kisa.Tests.csproj", "{9165A6AB-140D-41BC-91BC-44523D1C9978}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Nvd.Tests", "__Tests\StellaOps.Concelier.Connector.Nvd.Tests\StellaOps.Concelier.Connector.Nvd.Tests.csproj", "{A35677A8-170D-4933-B2C3-314A30920766}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Osv.Tests", "__Tests\StellaOps.Concelier.Connector.Osv.Tests\StellaOps.Concelier.Connector.Osv.Tests.csproj", "{E21AD10F-87B8-4C39-BE45-B6C44CE6D841}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Bdu.Tests", "__Tests\StellaOps.Concelier.Connector.Ru.Bdu.Tests\StellaOps.Concelier.Connector.Ru.Bdu.Tests.csproj", "{1E93E173-53B1-4441-97E0-C60A3FB029D7}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Nkcki.Tests", "__Tests\StellaOps.Concelier.Connector.Ru.Nkcki.Tests\StellaOps.Concelier.Connector.Ru.Nkcki.Tests.csproj", "{92827ACC-284F-44EB-98A7-94B57BA92D27}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.StellaOpsMirror.Tests", "__Tests\StellaOps.Concelier.Connector.StellaOpsMirror.Tests\StellaOps.Concelier.Connector.StellaOpsMirror.Tests.csproj", "{1B017E4D-6F3E-42D4-9418-DA8D76BA2797}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Adobe.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Adobe.Tests\StellaOps.Concelier.Connector.Vndr.Adobe.Tests.csproj", "{45A163F4-2569-40D9-8FF6-854AF95C061E}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Apple.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Apple.Tests\StellaOps.Concelier.Connector.Vndr.Apple.Tests.csproj", "{17934A3D-6420-48F2-A528-E32A34F0FE55}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Chromium.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Chromium.Tests\StellaOps.Concelier.Connector.Vndr.Chromium.Tests.csproj", "{07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Cisco.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Cisco.Tests\StellaOps.Concelier.Connector.Vndr.Cisco.Tests.csproj", "{D485A847-B3EA-40D8-A56A-459A02C902F8}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Msrc.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Msrc.Tests\StellaOps.Concelier.Connector.Vndr.Msrc.Tests.csproj", "{0B716CE2-810A-4143-8434-4DB111E0F3E9}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Oracle.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Oracle.Tests\StellaOps.Concelier.Connector.Vndr.Oracle.Tests.csproj", "{2A75CB97-ACF1-43B2-8509-E8226000D7DC}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Vmware.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Vmware.Tests\StellaOps.Concelier.Connector.Vndr.Vmware.Tests.csproj", "{3AEC19B5-44F6-4717-B1A0-3A2F04F42565}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Core.Tests", "__Tests\StellaOps.Concelier.Core.Tests\StellaOps.Concelier.Core.Tests.csproj", "{1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.Json.Tests", "__Tests\StellaOps.Concelier.Exporter.Json.Tests\StellaOps.Concelier.Exporter.Json.Tests.csproj", "{258A6D13-F02C-48C6-8506-2C815EBBD1D5}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.TrivyDb.Tests", "__Tests\StellaOps.Concelier.Exporter.TrivyDb.Tests\StellaOps.Concelier.Exporter.TrivyDb.Tests.csproj", "{39F8D963-3D76-4BEC-BE7B-4AE9C9664211}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Merge.Tests", "__Tests\StellaOps.Concelier.Merge.Tests\StellaOps.Concelier.Merge.Tests.csproj", "{470793D6-A847-41E3-A15D-8D0DFE7CD9A3}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Models.Tests", "__Tests\StellaOps.Concelier.Models.Tests\StellaOps.Concelier.Models.Tests.csproj", "{2EB876DE-E940-4A7E-8E3D-804E2E6314DA}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Normalization.Tests", "__Tests\StellaOps.Concelier.Normalization.Tests\StellaOps.Concelier.Normalization.Tests.csproj", "{C4C2037E-B301-4449-96D6-C6B165752E1A}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.RawModels.Tests", "__Tests\StellaOps.Concelier.RawModels.Tests\StellaOps.Concelier.RawModels.Tests.csproj", "{7B995CBB-3D20-4509-9300-EC012C18C4B4}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Storage.Mongo.Tests", "__Tests\StellaOps.Concelier.Storage.Mongo.Tests\StellaOps.Concelier.Storage.Mongo.Tests.csproj", "{9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}"
-EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.WebService.Tests", "__Tests\StellaOps.Concelier.WebService.Tests\StellaOps.Concelier.WebService.Tests.csproj", "{664A2577-6DA1-42DA-A213-3253017FA4BF}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Debug|x64 = Debug|x64
- Debug|x86 = Debug|x86
- Release|Any CPU = Release|Any CPU
- Release|x64 = Release|x64
- Release|x86 = Release|x86
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x64.ActiveCfg = Debug|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x64.Build.0 = Debug|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x86.ActiveCfg = Debug|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x86.Build.0 = Debug|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|Any CPU.Build.0 = Release|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x64.ActiveCfg = Release|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x64.Build.0 = Release|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x86.ActiveCfg = Release|Any CPU
- {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x86.Build.0 = Release|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x64.ActiveCfg = Debug|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x64.Build.0 = Debug|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x86.ActiveCfg = Debug|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x86.Build.0 = Debug|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|Any CPU.Build.0 = Release|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x64.ActiveCfg = Release|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x64.Build.0 = Release|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x86.ActiveCfg = Release|Any CPU
- {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x86.Build.0 = Release|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x64.ActiveCfg = Debug|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x64.Build.0 = Debug|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x86.ActiveCfg = Debug|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x86.Build.0 = Debug|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|Any CPU.Build.0 = Release|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x64.ActiveCfg = Release|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x64.Build.0 = Release|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x86.ActiveCfg = Release|Any CPU
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x86.Build.0 = Release|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x64.ActiveCfg = Debug|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x64.Build.0 = Debug|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x86.ActiveCfg = Debug|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x86.Build.0 = Debug|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|Any CPU.Build.0 = Release|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x64.ActiveCfg = Release|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x64.Build.0 = Release|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x86.ActiveCfg = Release|Any CPU
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x86.Build.0 = Release|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x64.Build.0 = Debug|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x86.ActiveCfg = Debug|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x86.Build.0 = Debug|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|Any CPU.Build.0 = Release|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x64.ActiveCfg = Release|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x64.Build.0 = Release|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x86.ActiveCfg = Release|Any CPU
- {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x86.Build.0 = Release|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x64.Build.0 = Debug|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x86.Build.0 = Debug|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|Any CPU.Build.0 = Release|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x64.ActiveCfg = Release|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x64.Build.0 = Release|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x86.ActiveCfg = Release|Any CPU
- {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x86.Build.0 = Release|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x64.Build.0 = Debug|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x86.Build.0 = Debug|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Release|Any CPU.Build.0 = Release|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Release|x64.ActiveCfg = Release|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Release|x64.Build.0 = Release|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Release|x86.ActiveCfg = Release|Any CPU
- {7B48F422-65E3-464B-B029-0766207035EB}.Release|x86.Build.0 = Release|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x64.Build.0 = Debug|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x86.Build.0 = Debug|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|Any CPU.Build.0 = Release|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x64.ActiveCfg = Release|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x64.Build.0 = Release|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x86.ActiveCfg = Release|Any CPU
- {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x86.Build.0 = Release|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x64.Build.0 = Debug|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x86.Build.0 = Debug|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|Any CPU.Build.0 = Release|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x64.ActiveCfg = Release|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x64.Build.0 = Release|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x86.ActiveCfg = Release|Any CPU
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x86.Build.0 = Release|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x64.Build.0 = Debug|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x86.Build.0 = Debug|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|Any CPU.Build.0 = Release|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x64.ActiveCfg = Release|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x64.Build.0 = Release|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x86.ActiveCfg = Release|Any CPU
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x86.Build.0 = Release|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x64.Build.0 = Debug|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x86.Build.0 = Debug|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|Any CPU.Build.0 = Release|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x64.ActiveCfg = Release|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x64.Build.0 = Release|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x86.ActiveCfg = Release|Any CPU
- {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x86.Build.0 = Release|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x64.ActiveCfg = Debug|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x64.Build.0 = Debug|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x86.ActiveCfg = Debug|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x86.Build.0 = Debug|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|Any CPU.Build.0 = Release|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x64.ActiveCfg = Release|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x64.Build.0 = Release|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x86.ActiveCfg = Release|Any CPU
- {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x86.Build.0 = Release|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x64.ActiveCfg = Debug|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x64.Build.0 = Debug|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x86.ActiveCfg = Debug|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x86.Build.0 = Debug|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|Any CPU.Build.0 = Release|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x64.ActiveCfg = Release|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x64.Build.0 = Release|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x86.ActiveCfg = Release|Any CPU
- {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x86.Build.0 = Release|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x64.Build.0 = Debug|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x86.Build.0 = Debug|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Release|Any CPU.Build.0 = Release|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x64.ActiveCfg = Release|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x64.Build.0 = Release|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x86.ActiveCfg = Release|Any CPU
- {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x86.Build.0 = Release|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x64.Build.0 = Debug|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x86.Build.0 = Debug|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|Any CPU.Build.0 = Release|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x64.ActiveCfg = Release|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x64.Build.0 = Release|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x86.ActiveCfg = Release|Any CPU
- {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x86.Build.0 = Release|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x64.Build.0 = Debug|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x86.Build.0 = Debug|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|Any CPU.Build.0 = Release|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x64.ActiveCfg = Release|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x64.Build.0 = Release|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x86.ActiveCfg = Release|Any CPU
- {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x86.Build.0 = Release|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x64.Build.0 = Debug|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x86.Build.0 = Debug|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|Any CPU.Build.0 = Release|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x64.ActiveCfg = Release|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x64.Build.0 = Release|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x86.ActiveCfg = Release|Any CPU
- {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x86.Build.0 = Release|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x64.Build.0 = Debug|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x86.Build.0 = Debug|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|Any CPU.Build.0 = Release|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x64.ActiveCfg = Release|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x64.Build.0 = Release|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x86.ActiveCfg = Release|Any CPU
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x86.Build.0 = Release|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x64.Build.0 = Debug|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x86.ActiveCfg = Debug|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x86.Build.0 = Debug|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|Any CPU.Build.0 = Release|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x64.ActiveCfg = Release|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x64.Build.0 = Release|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x86.ActiveCfg = Release|Any CPU
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x86.Build.0 = Release|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x64.ActiveCfg = Debug|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x64.Build.0 = Debug|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x86.ActiveCfg = Debug|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x86.Build.0 = Debug|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|Any CPU.Build.0 = Release|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x64.ActiveCfg = Release|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x64.Build.0 = Release|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x86.ActiveCfg = Release|Any CPU
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x86.Build.0 = Release|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x64.Build.0 = Debug|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x86.Build.0 = Debug|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|Any CPU.Build.0 = Release|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x64.ActiveCfg = Release|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x64.Build.0 = Release|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x86.ActiveCfg = Release|Any CPU
- {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x86.Build.0 = Release|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x64.ActiveCfg = Debug|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x64.Build.0 = Debug|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x86.ActiveCfg = Debug|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x86.Build.0 = Debug|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|Any CPU.Build.0 = Release|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x64.ActiveCfg = Release|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x64.Build.0 = Release|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x86.ActiveCfg = Release|Any CPU
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x86.Build.0 = Release|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x64.Build.0 = Debug|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x86.Build.0 = Debug|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|Any CPU.Build.0 = Release|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x64.ActiveCfg = Release|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x64.Build.0 = Release|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x86.ActiveCfg = Release|Any CPU
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x86.Build.0 = Release|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x64.ActiveCfg = Debug|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x64.Build.0 = Debug|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x86.ActiveCfg = Debug|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x86.Build.0 = Debug|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|Any CPU.Build.0 = Release|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x64.ActiveCfg = Release|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x64.Build.0 = Release|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x86.ActiveCfg = Release|Any CPU
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x86.Build.0 = Release|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x64.Build.0 = Debug|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x86.Build.0 = Debug|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|Any CPU.Build.0 = Release|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x64.ActiveCfg = Release|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x64.Build.0 = Release|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x86.ActiveCfg = Release|Any CPU
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x86.Build.0 = Release|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x64.Build.0 = Debug|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x86.Build.0 = Debug|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|Any CPU.Build.0 = Release|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x64.ActiveCfg = Release|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x64.Build.0 = Release|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x86.ActiveCfg = Release|Any CPU
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x86.Build.0 = Release|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x64.Build.0 = Debug|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x86.Build.0 = Debug|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|Any CPU.Build.0 = Release|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x64.ActiveCfg = Release|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x64.Build.0 = Release|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x86.ActiveCfg = Release|Any CPU
- {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x86.Build.0 = Release|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x64.Build.0 = Debug|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x86.Build.0 = Debug|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|Any CPU.Build.0 = Release|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x64.ActiveCfg = Release|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x64.Build.0 = Release|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x86.ActiveCfg = Release|Any CPU
- {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x86.Build.0 = Release|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x64.ActiveCfg = Debug|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x64.Build.0 = Debug|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x86.ActiveCfg = Debug|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x86.Build.0 = Debug|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|Any CPU.Build.0 = Release|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x64.ActiveCfg = Release|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x64.Build.0 = Release|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x86.ActiveCfg = Release|Any CPU
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x86.Build.0 = Release|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x64.Build.0 = Debug|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x86.Build.0 = Debug|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|Any CPU.Build.0 = Release|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x64.ActiveCfg = Release|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x64.Build.0 = Release|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x86.ActiveCfg = Release|Any CPU
- {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x86.Build.0 = Release|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x64.Build.0 = Debug|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x86.Build.0 = Debug|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|Any CPU.Build.0 = Release|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x64.ActiveCfg = Release|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x64.Build.0 = Release|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x86.ActiveCfg = Release|Any CPU
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x86.Build.0 = Release|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x64.ActiveCfg = Debug|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x64.Build.0 = Debug|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x86.ActiveCfg = Debug|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x86.Build.0 = Debug|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|Any CPU.Build.0 = Release|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x64.ActiveCfg = Release|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x64.Build.0 = Release|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x86.ActiveCfg = Release|Any CPU
- {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x86.Build.0 = Release|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x64.Build.0 = Debug|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x86.Build.0 = Debug|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|Any CPU.Build.0 = Release|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x64.ActiveCfg = Release|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x64.Build.0 = Release|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x86.ActiveCfg = Release|Any CPU
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x86.Build.0 = Release|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x64.Build.0 = Debug|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x86.Build.0 = Debug|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|Any CPU.Build.0 = Release|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x64.ActiveCfg = Release|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x64.Build.0 = Release|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x86.ActiveCfg = Release|Any CPU
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x86.Build.0 = Release|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x64.ActiveCfg = Debug|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x64.Build.0 = Debug|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x86.ActiveCfg = Debug|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x86.Build.0 = Debug|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|Any CPU.Build.0 = Release|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x64.ActiveCfg = Release|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x64.Build.0 = Release|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x86.ActiveCfg = Release|Any CPU
- {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x86.Build.0 = Release|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x64.ActiveCfg = Debug|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x64.Build.0 = Debug|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x86.ActiveCfg = Debug|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x86.Build.0 = Debug|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|Any CPU.Build.0 = Release|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x64.ActiveCfg = Release|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x64.Build.0 = Release|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x86.ActiveCfg = Release|Any CPU
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x86.Build.0 = Release|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x64.ActiveCfg = Debug|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x64.Build.0 = Debug|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x86.ActiveCfg = Debug|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x86.Build.0 = Debug|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Release|Any CPU.Build.0 = Release|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x64.ActiveCfg = Release|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x64.Build.0 = Release|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x86.ActiveCfg = Release|Any CPU
- {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x86.Build.0 = Release|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x64.Build.0 = Debug|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x86.Build.0 = Debug|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|Any CPU.Build.0 = Release|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x64.ActiveCfg = Release|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x64.Build.0 = Release|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x86.ActiveCfg = Release|Any CPU
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x86.Build.0 = Release|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x64.ActiveCfg = Debug|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x64.Build.0 = Debug|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x86.ActiveCfg = Debug|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x86.Build.0 = Debug|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|Any CPU.Build.0 = Release|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x64.ActiveCfg = Release|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x64.Build.0 = Release|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x86.ActiveCfg = Release|Any CPU
- {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x86.Build.0 = Release|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x64.ActiveCfg = Debug|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x64.Build.0 = Debug|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x86.ActiveCfg = Debug|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x86.Build.0 = Debug|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|Any CPU.Build.0 = Release|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x64.ActiveCfg = Release|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x64.Build.0 = Release|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x86.ActiveCfg = Release|Any CPU
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x86.Build.0 = Release|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x64.ActiveCfg = Debug|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x64.Build.0 = Debug|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x86.ActiveCfg = Debug|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x86.Build.0 = Debug|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|Any CPU.Build.0 = Release|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x64.ActiveCfg = Release|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x64.Build.0 = Release|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x86.ActiveCfg = Release|Any CPU
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x86.Build.0 = Release|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x64.ActiveCfg = Debug|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x64.Build.0 = Debug|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x86.ActiveCfg = Debug|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x86.Build.0 = Debug|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|Any CPU.Build.0 = Release|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x64.ActiveCfg = Release|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x64.Build.0 = Release|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x86.ActiveCfg = Release|Any CPU
- {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x86.Build.0 = Release|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x64.ActiveCfg = Debug|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x64.Build.0 = Debug|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x86.ActiveCfg = Debug|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x86.Build.0 = Debug|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|Any CPU.Build.0 = Release|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x64.ActiveCfg = Release|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x64.Build.0 = Release|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x86.ActiveCfg = Release|Any CPU
- {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x86.Build.0 = Release|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x64.ActiveCfg = Debug|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x64.Build.0 = Debug|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x86.ActiveCfg = Debug|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x86.Build.0 = Debug|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|Any CPU.Build.0 = Release|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x64.ActiveCfg = Release|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x64.Build.0 = Release|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x86.ActiveCfg = Release|Any CPU
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x86.Build.0 = Release|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x64.ActiveCfg = Debug|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x64.Build.0 = Debug|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x86.ActiveCfg = Debug|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x86.Build.0 = Debug|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|Any CPU.Build.0 = Release|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x64.ActiveCfg = Release|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x64.Build.0 = Release|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x86.ActiveCfg = Release|Any CPU
- {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x86.Build.0 = Release|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x64.ActiveCfg = Debug|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x64.Build.0 = Debug|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x86.ActiveCfg = Debug|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x86.Build.0 = Debug|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|Any CPU.Build.0 = Release|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x64.ActiveCfg = Release|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x64.Build.0 = Release|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x86.ActiveCfg = Release|Any CPU
- {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x86.Build.0 = Release|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x64.Build.0 = Debug|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x86.Build.0 = Debug|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|Any CPU.Build.0 = Release|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x64.ActiveCfg = Release|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x64.Build.0 = Release|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x86.ActiveCfg = Release|Any CPU
- {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x86.Build.0 = Release|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x64.Build.0 = Debug|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x86.ActiveCfg = Debug|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x86.Build.0 = Debug|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|Any CPU.Build.0 = Release|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x64.ActiveCfg = Release|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x64.Build.0 = Release|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x86.ActiveCfg = Release|Any CPU
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x86.Build.0 = Release|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x64.Build.0 = Debug|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x86.Build.0 = Debug|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|Any CPU.Build.0 = Release|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x64.ActiveCfg = Release|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x64.Build.0 = Release|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x86.ActiveCfg = Release|Any CPU
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x86.Build.0 = Release|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x64.Build.0 = Debug|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x86.Build.0 = Debug|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|Any CPU.Build.0 = Release|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x64.ActiveCfg = Release|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x64.Build.0 = Release|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x86.ActiveCfg = Release|Any CPU
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x86.Build.0 = Release|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x64.ActiveCfg = Debug|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x64.Build.0 = Debug|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x86.ActiveCfg = Debug|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x86.Build.0 = Debug|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|Any CPU.Build.0 = Release|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x64.ActiveCfg = Release|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x64.Build.0 = Release|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x86.ActiveCfg = Release|Any CPU
- {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x86.Build.0 = Release|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x64.ActiveCfg = Debug|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x64.Build.0 = Debug|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x86.ActiveCfg = Debug|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x86.Build.0 = Debug|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|Any CPU.Build.0 = Release|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x64.ActiveCfg = Release|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x64.Build.0 = Release|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x86.ActiveCfg = Release|Any CPU
- {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x86.Build.0 = Release|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x64.Build.0 = Debug|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x86.Build.0 = Debug|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|Any CPU.Build.0 = Release|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x64.ActiveCfg = Release|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x64.Build.0 = Release|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x86.ActiveCfg = Release|Any CPU
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x86.Build.0 = Release|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x64.Build.0 = Debug|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x86.Build.0 = Debug|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|Any CPU.Build.0 = Release|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x64.ActiveCfg = Release|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x64.Build.0 = Release|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x86.ActiveCfg = Release|Any CPU
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x86.Build.0 = Release|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x64.Build.0 = Debug|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x86.Build.0 = Debug|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|Any CPU.Build.0 = Release|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x64.ActiveCfg = Release|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x64.Build.0 = Release|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x86.ActiveCfg = Release|Any CPU
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x86.Build.0 = Release|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x64.ActiveCfg = Debug|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x64.Build.0 = Debug|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x86.ActiveCfg = Debug|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x86.Build.0 = Debug|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|Any CPU.Build.0 = Release|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x64.ActiveCfg = Release|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x64.Build.0 = Release|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x86.ActiveCfg = Release|Any CPU
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x86.Build.0 = Release|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x64.ActiveCfg = Debug|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x64.Build.0 = Debug|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x86.ActiveCfg = Debug|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x86.Build.0 = Debug|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|Any CPU.Build.0 = Release|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x64.ActiveCfg = Release|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x64.Build.0 = Release|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x86.ActiveCfg = Release|Any CPU
- {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x86.Build.0 = Release|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x64.Build.0 = Debug|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x86.Build.0 = Debug|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|Any CPU.Build.0 = Release|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x64.ActiveCfg = Release|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x64.Build.0 = Release|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x86.ActiveCfg = Release|Any CPU
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x86.Build.0 = Release|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x64.Build.0 = Debug|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x86.Build.0 = Debug|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|Any CPU.Build.0 = Release|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x64.ActiveCfg = Release|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x64.Build.0 = Release|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x86.ActiveCfg = Release|Any CPU
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x86.Build.0 = Release|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x64.ActiveCfg = Debug|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x64.Build.0 = Debug|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x86.ActiveCfg = Debug|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x86.Build.0 = Debug|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|Any CPU.Build.0 = Release|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x64.ActiveCfg = Release|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x64.Build.0 = Release|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x86.ActiveCfg = Release|Any CPU
- {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x86.Build.0 = Release|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x64.ActiveCfg = Debug|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x64.Build.0 = Debug|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x86.ActiveCfg = Debug|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x86.Build.0 = Debug|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|Any CPU.Build.0 = Release|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x64.ActiveCfg = Release|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x64.Build.0 = Release|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x86.ActiveCfg = Release|Any CPU
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x86.Build.0 = Release|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x64.Build.0 = Debug|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x86.Build.0 = Debug|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|Any CPU.Build.0 = Release|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x64.ActiveCfg = Release|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x64.Build.0 = Release|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x86.ActiveCfg = Release|Any CPU
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x86.Build.0 = Release|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x64.ActiveCfg = Debug|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x64.Build.0 = Debug|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x86.ActiveCfg = Debug|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x86.Build.0 = Debug|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|Any CPU.Build.0 = Release|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x64.ActiveCfg = Release|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x64.Build.0 = Release|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x86.ActiveCfg = Release|Any CPU
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x86.Build.0 = Release|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x64.Build.0 = Debug|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x86.Build.0 = Debug|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|Any CPU.Build.0 = Release|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x64.ActiveCfg = Release|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x64.Build.0 = Release|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x86.ActiveCfg = Release|Any CPU
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x86.Build.0 = Release|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x64.ActiveCfg = Debug|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x64.Build.0 = Debug|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x86.ActiveCfg = Debug|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x86.Build.0 = Debug|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|Any CPU.Build.0 = Release|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x64.ActiveCfg = Release|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x64.Build.0 = Release|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x86.ActiveCfg = Release|Any CPU
- {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x86.Build.0 = Release|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x64.ActiveCfg = Debug|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x64.Build.0 = Debug|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x86.ActiveCfg = Debug|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x86.Build.0 = Debug|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|Any CPU.Build.0 = Release|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x64.ActiveCfg = Release|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x64.Build.0 = Release|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x86.ActiveCfg = Release|Any CPU
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x86.Build.0 = Release|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x64.ActiveCfg = Debug|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x64.Build.0 = Debug|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x86.ActiveCfg = Debug|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x86.Build.0 = Debug|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|Any CPU.Build.0 = Release|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x64.ActiveCfg = Release|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x64.Build.0 = Release|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x86.ActiveCfg = Release|Any CPU
- {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x86.Build.0 = Release|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x64.ActiveCfg = Debug|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x64.Build.0 = Debug|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x86.ActiveCfg = Debug|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x86.Build.0 = Debug|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Release|Any CPU.Build.0 = Release|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Release|x64.ActiveCfg = Release|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Release|x64.Build.0 = Release|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Release|x86.ActiveCfg = Release|Any CPU
- {A35677A8-170D-4933-B2C3-314A30920766}.Release|x86.Build.0 = Release|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x64.ActiveCfg = Debug|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x64.Build.0 = Debug|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x86.ActiveCfg = Debug|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x86.Build.0 = Debug|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|Any CPU.Build.0 = Release|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x64.ActiveCfg = Release|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x64.Build.0 = Release|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x86.ActiveCfg = Release|Any CPU
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x86.Build.0 = Release|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x64.Build.0 = Debug|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x86.Build.0 = Debug|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|Any CPU.Build.0 = Release|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x64.ActiveCfg = Release|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x64.Build.0 = Release|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x86.ActiveCfg = Release|Any CPU
- {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x86.Build.0 = Release|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x64.ActiveCfg = Debug|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x64.Build.0 = Debug|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x86.ActiveCfg = Debug|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x86.Build.0 = Debug|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|Any CPU.Build.0 = Release|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x64.ActiveCfg = Release|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x64.Build.0 = Release|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x86.ActiveCfg = Release|Any CPU
- {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x86.Build.0 = Release|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x64.Build.0 = Debug|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x86.Build.0 = Debug|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|Any CPU.Build.0 = Release|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x64.ActiveCfg = Release|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x64.Build.0 = Release|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x86.ActiveCfg = Release|Any CPU
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x86.Build.0 = Release|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x64.ActiveCfg = Debug|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x64.Build.0 = Debug|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x86.ActiveCfg = Debug|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x86.Build.0 = Debug|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|Any CPU.Build.0 = Release|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x64.ActiveCfg = Release|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x64.Build.0 = Release|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x86.ActiveCfg = Release|Any CPU
- {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x86.Build.0 = Release|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x64.ActiveCfg = Debug|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x64.Build.0 = Debug|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x86.ActiveCfg = Debug|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x86.Build.0 = Debug|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|Any CPU.Build.0 = Release|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x64.ActiveCfg = Release|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x64.Build.0 = Release|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x86.ActiveCfg = Release|Any CPU
- {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x86.Build.0 = Release|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x64.ActiveCfg = Debug|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x64.Build.0 = Debug|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x86.ActiveCfg = Debug|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x86.Build.0 = Debug|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|Any CPU.Build.0 = Release|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x64.ActiveCfg = Release|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x64.Build.0 = Release|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x86.ActiveCfg = Release|Any CPU
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x86.Build.0 = Release|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x64.ActiveCfg = Debug|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x64.Build.0 = Debug|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x86.ActiveCfg = Debug|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x86.Build.0 = Debug|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|Any CPU.Build.0 = Release|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x64.ActiveCfg = Release|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x64.Build.0 = Release|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x86.ActiveCfg = Release|Any CPU
- {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x86.Build.0 = Release|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x64.ActiveCfg = Debug|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x64.Build.0 = Debug|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x86.ActiveCfg = Debug|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x86.Build.0 = Debug|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|Any CPU.Build.0 = Release|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x64.ActiveCfg = Release|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x64.Build.0 = Release|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x86.ActiveCfg = Release|Any CPU
- {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x86.Build.0 = Release|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x64.Build.0 = Debug|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x86.Build.0 = Debug|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|Any CPU.Build.0 = Release|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x64.ActiveCfg = Release|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x64.Build.0 = Release|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x86.ActiveCfg = Release|Any CPU
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x86.Build.0 = Release|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x64.ActiveCfg = Debug|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x64.Build.0 = Debug|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x86.ActiveCfg = Debug|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x86.Build.0 = Debug|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|Any CPU.Build.0 = Release|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x64.ActiveCfg = Release|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x64.Build.0 = Release|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x86.ActiveCfg = Release|Any CPU
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x86.Build.0 = Release|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x64.ActiveCfg = Debug|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x64.Build.0 = Debug|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x86.ActiveCfg = Debug|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x86.Build.0 = Debug|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|Any CPU.Build.0 = Release|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x64.ActiveCfg = Release|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x64.Build.0 = Release|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x86.ActiveCfg = Release|Any CPU
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x86.Build.0 = Release|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x64.ActiveCfg = Debug|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x64.Build.0 = Debug|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x86.ActiveCfg = Debug|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x86.Build.0 = Debug|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|Any CPU.Build.0 = Release|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x64.ActiveCfg = Release|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x64.Build.0 = Release|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x86.ActiveCfg = Release|Any CPU
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x86.Build.0 = Release|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x64.ActiveCfg = Debug|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x64.Build.0 = Debug|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x86.ActiveCfg = Debug|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x86.Build.0 = Debug|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|Any CPU.Build.0 = Release|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x64.ActiveCfg = Release|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x64.Build.0 = Release|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x86.ActiveCfg = Release|Any CPU
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x86.Build.0 = Release|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x64.ActiveCfg = Debug|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x64.Build.0 = Debug|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x86.ActiveCfg = Debug|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x86.Build.0 = Debug|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|Any CPU.Build.0 = Release|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x64.ActiveCfg = Release|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x64.Build.0 = Release|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x86.ActiveCfg = Release|Any CPU
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x86.Build.0 = Release|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x64.ActiveCfg = Debug|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x64.Build.0 = Debug|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x86.ActiveCfg = Debug|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x86.Build.0 = Debug|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|Any CPU.Build.0 = Release|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x64.ActiveCfg = Release|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x64.Build.0 = Release|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x86.ActiveCfg = Release|Any CPU
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x86.Build.0 = Release|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x64.ActiveCfg = Debug|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x64.Build.0 = Debug|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x86.ActiveCfg = Debug|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x86.Build.0 = Debug|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|Any CPU.Build.0 = Release|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x64.ActiveCfg = Release|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x64.Build.0 = Release|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x86.ActiveCfg = Release|Any CPU
- {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x86.Build.0 = Release|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x64.ActiveCfg = Debug|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x64.Build.0 = Debug|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x86.ActiveCfg = Debug|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x86.Build.0 = Debug|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|Any CPU.Build.0 = Release|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x64.ActiveCfg = Release|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x64.Build.0 = Release|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x86.ActiveCfg = Release|Any CPU
- {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x86.Build.0 = Release|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x64.ActiveCfg = Debug|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x64.Build.0 = Debug|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x86.ActiveCfg = Debug|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x86.Build.0 = Debug|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|Any CPU.Build.0 = Release|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x64.ActiveCfg = Release|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x64.Build.0 = Release|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x86.ActiveCfg = Release|Any CPU
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x86.Build.0 = Release|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x64.ActiveCfg = Debug|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x64.Build.0 = Debug|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x86.ActiveCfg = Debug|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x86.Build.0 = Debug|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|Any CPU.Build.0 = Release|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x64.ActiveCfg = Release|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x64.Build.0 = Release|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x86.ActiveCfg = Release|Any CPU
- {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x86.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
- GlobalSection(NestedProjects) = preSolution
- {D93F34C2-5E5E-4CC7-A573-4376AA525838} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {EEC52FA0-8E78-4FCB-9454-D697F58B2118} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {628700D6-97A5-4506-BC78-22E2A76C68E3} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {C926373D-5ACB-4E62-96D5-264EF4C61BE5} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {2D68125A-0ACD-4015-A8FA-B54284B8A3CB} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {7760219F-6C19-4B61-9015-73BB02005C0B} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {77FF9993-C811-4389-8BFE-974B4F0AB7C6} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {4FB18D5B-8D48-4E50-9608-69890B3420F8} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {257E2D7B-EA3D-4B33-9546-7B77DA20A517} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {C827F73E-68E2-4F6A-8CEA-0425B2D2D466} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {F67EECB0-7DCC-4643-82F3-E020D72BE762} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {2975AE79-F23D-43D6-B075-6659AB6AE105} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {667ACFE7-922E-4958-99D6-DD9D7BE8E744} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {D4824290-3F8A-47BD-A368-F63BE593546B} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {33C98234-DF04-40CE-9459-2736AAB0CF6C} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {A6D364F9-3478-4432-9EE1-F4F3DCF125EA} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {B9EDA23E-5754-48AF-8978-DBCBF75134BF} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {9208F373-EDD1-491D-AEF9-FE280B453CD9} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {EC5DE6F3-D158-4261-A4CD-AB81AE154918} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {40591EC3-23C6-4E74-8280-35153641FF21} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {5646F7F2-FEDF-49D1-9053-F8E1B7892695} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {3C877F0B-3870-452B-AA70-1F9960A4F062} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {5525AD40-01DA-46DD-B331-DD032DD3C9C0} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {296A426A-E429-4984-8813-AA7EEE3037D5} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {6F1AB15F-8875-4A62-A878-842D463A3B11} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {8EFE438F-0513-470C-909B-8A1BD62D0E98} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {60712A8D-FF22-452C-8AC0-22DB33B38180} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {4097C3CB-7C39-478B-89C2-4D317625EBBF} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {935D16AC-8EBD-46E4-8D0E-934F3AE961D4} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {0BC8276D-D726-4C8B-AB2B-122BE18F1112} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
- {654CF4EE-9EC5-464C-AF47-EE37329CD46A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {BEF6FA33-E0EA-4ED2-B209-833D41607132} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {B777945B-92DB-4D24-A795-5C900B6FCB92} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {F90FCF19-0426-4E62-93DC-835712E5B064} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {0E84E05F-53CE-4A6E-95F0-62EF14CBC385} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {4DD7C512-5624-4C6B-B02A-7EDF58242657} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {98AA9471-2498-45BC-A58F-B83F4B9A8B75} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {253BAF8F-0CF8-4D1A-B5AA-F19713099173} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {57A423CD-4F40-4BAD-A6FC-93D494FCA51A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {07034F70-3E4F-49BF-A181-75443D3B3361} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {9165A6AB-140D-41BC-91BC-44523D1C9978} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {A35677A8-170D-4933-B2C3-314A30920766} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {E21AD10F-87B8-4C39-BE45-B6C44CE6D841} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {1E93E173-53B1-4441-97E0-C60A3FB029D7} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {92827ACC-284F-44EB-98A7-94B57BA92D27} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {1B017E4D-6F3E-42D4-9418-DA8D76BA2797} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {45A163F4-2569-40D9-8FF6-854AF95C061E} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {17934A3D-6420-48F2-A528-E32A34F0FE55} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {D485A847-B3EA-40D8-A56A-459A02C902F8} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {0B716CE2-810A-4143-8434-4DB111E0F3E9} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {2A75CB97-ACF1-43B2-8509-E8226000D7DC} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {3AEC19B5-44F6-4717-B1A0-3A2F04F42565} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {258A6D13-F02C-48C6-8506-2C815EBBD1D5} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {39F8D963-3D76-4BEC-BE7B-4AE9C9664211} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {470793D6-A847-41E3-A15D-8D0DFE7CD9A3} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {2EB876DE-E940-4A7E-8E3D-804E2E6314DA} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {C4C2037E-B301-4449-96D6-C6B165752E1A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {7B995CBB-3D20-4509-9300-EC012C18C4B4} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- {664A2577-6DA1-42DA-A213-3253017FA4BF} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
- EndGlobalSection
-EndGlobal
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.0.31903.59
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.WebService", "StellaOps.Concelier.WebService\StellaOps.Concelier.WebService.csproj", "{FB98E71B-AF9D-4593-8306-F989C2CA2BBE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Libraries", "__Libraries", "{41F15E67-7190-CF23-3BC4-77E87134CADD}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Core", "__Libraries\StellaOps.Concelier.Core\StellaOps.Concelier.Core.csproj", "{D93F34C2-5E5E-4CC7-A573-4376AA525838}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Models", "__Libraries\StellaOps.Concelier.Models\StellaOps.Concelier.Models.csproj", "{841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.RawModels", "__Libraries\StellaOps.Concelier.RawModels\StellaOps.Concelier.RawModels.csproj", "{EEC52FA0-8E78-4FCB-9454-D697F58B2118}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Normalization", "__Libraries\StellaOps.Concelier.Normalization\StellaOps.Concelier.Normalization.csproj", "{628700D6-97A5-4506-BC78-22E2A76C68E3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Plugin", "..\__Libraries\StellaOps.Plugin\StellaOps.Plugin.csproj", "{A3E52755-5B68-4A33-9078-893A7FEE7D4B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.DependencyInjection", "..\__Libraries\StellaOps.DependencyInjection\StellaOps.DependencyInjection.csproj", "{7B48F422-65E3-464B-B029-0766207035EB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Aoc", "..\Aoc\__Libraries\StellaOps.Aoc\StellaOps.Aoc.csproj", "{A6802486-A8D3-4623-8D81-04ED23F9D312}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Storage.Mongo", "__Libraries\StellaOps.Concelier.Storage.Mongo\StellaOps.Concelier.Storage.Mongo.csproj", "{C926373D-5ACB-4E62-96D5-264EF4C61BE5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Common", "__Libraries\StellaOps.Concelier.Connector.Common\StellaOps.Concelier.Connector.Common.csproj", "{2D68125A-0ACD-4015-A8FA-B54284B8A3CB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Merge", "__Libraries\StellaOps.Concelier.Merge\StellaOps.Concelier.Merge.csproj", "{7760219F-6C19-4B61-9015-73BB02005C0B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Configuration", "..\__Libraries\StellaOps.Configuration\StellaOps.Configuration.csproj", "{EDD39EE5-8341-4BB0-9C30-D829D97C1E65}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Authority.Plugins.Abstractions", "..\Authority\StellaOps.Authority\StellaOps.Authority.Plugins.Abstractions\StellaOps.Authority.Plugins.Abstractions.csproj", "{80E7B08C-2916-4540-A34B-CB581EEEA202}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Cryptography", "..\__Libraries\StellaOps.Cryptography\StellaOps.Cryptography.csproj", "{5B04974C-EC04-446E-83C1-EF9686433586}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Auth.Abstractions", "..\Authority\StellaOps.Authority\StellaOps.Auth.Abstractions\StellaOps.Auth.Abstractions.csproj", "{1282AA12-C27D-4F85-B534-785FEFF52D5F}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Auth.Client", "..\Authority\StellaOps.Authority\StellaOps.Auth.Client\StellaOps.Auth.Client.csproj", "{C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Auth.ServerIntegration", "..\Authority\StellaOps.Authority\StellaOps.Auth.ServerIntegration\StellaOps.Auth.ServerIntegration.csproj", "{A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Acsc", "__Libraries\StellaOps.Concelier.Connector.Acsc\StellaOps.Concelier.Connector.Acsc.csproj", "{F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cccs", "__Libraries\StellaOps.Concelier.Connector.Cccs\StellaOps.Concelier.Connector.Cccs.csproj", "{30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertBund", "__Libraries\StellaOps.Concelier.Connector.CertBund\StellaOps.Concelier.Connector.CertBund.csproj", "{77FF9993-C811-4389-8BFE-974B4F0AB7C6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertCc", "__Libraries\StellaOps.Concelier.Connector.CertCc\StellaOps.Concelier.Connector.CertCc.csproj", "{4FB18D5B-8D48-4E50-9608-69890B3420F8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertFr", "__Libraries\StellaOps.Concelier.Connector.CertFr\StellaOps.Concelier.Connector.CertFr.csproj", "{585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertIn", "__Libraries\StellaOps.Concelier.Connector.CertIn\StellaOps.Concelier.Connector.CertIn.csproj", "{BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cve", "__Libraries\StellaOps.Concelier.Connector.Cve\StellaOps.Concelier.Connector.Cve.csproj", "{257E2D7B-EA3D-4B33-9546-7B77DA20A517}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Debian", "__Libraries\StellaOps.Concelier.Connector.Distro.Debian\StellaOps.Concelier.Connector.Distro.Debian.csproj", "{5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.RedHat", "__Libraries\StellaOps.Concelier.Connector.Distro.RedHat\StellaOps.Concelier.Connector.Distro.RedHat.csproj", "{C827F73E-68E2-4F6A-8CEA-0425B2D2D466}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Suse", "__Libraries\StellaOps.Concelier.Connector.Distro.Suse\StellaOps.Concelier.Connector.Distro.Suse.csproj", "{F67EECB0-7DCC-4643-82F3-E020D72BE762}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Ubuntu", "__Libraries\StellaOps.Concelier.Connector.Distro.Ubuntu\StellaOps.Concelier.Connector.Distro.Ubuntu.csproj", "{2975AE79-F23D-43D6-B075-6659AB6AE105}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ghsa", "__Libraries\StellaOps.Concelier.Connector.Ghsa\StellaOps.Concelier.Connector.Ghsa.csproj", "{667ACFE7-922E-4958-99D6-DD9D7BE8E744}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Cisa", "__Libraries\StellaOps.Concelier.Connector.Ics.Cisa\StellaOps.Concelier.Connector.Ics.Cisa.csproj", "{D4824290-3F8A-47BD-A368-F63BE593546B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Kaspersky", "__Libraries\StellaOps.Concelier.Connector.Ics.Kaspersky\StellaOps.Concelier.Connector.Ics.Kaspersky.csproj", "{B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Jvn", "__Libraries\StellaOps.Concelier.Connector.Jvn\StellaOps.Concelier.Connector.Jvn.csproj", "{33C98234-DF04-40CE-9459-2736AAB0CF6C}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kev", "__Libraries\StellaOps.Concelier.Connector.Kev\StellaOps.Concelier.Connector.Kev.csproj", "{A6D364F9-3478-4432-9EE1-F4F3DCF125EA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kisa", "__Libraries\StellaOps.Concelier.Connector.Kisa\StellaOps.Concelier.Connector.Kisa.csproj", "{B9EDA23E-5754-48AF-8978-DBCBF75134BF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Nvd", "__Libraries\StellaOps.Concelier.Connector.Nvd\StellaOps.Concelier.Connector.Nvd.csproj", "{9208F373-EDD1-491D-AEF9-FE280B453CD9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Osv", "__Libraries\StellaOps.Concelier.Connector.Osv\StellaOps.Concelier.Connector.Osv.csproj", "{EC5DE6F3-D158-4261-A4CD-AB81AE154918}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Bdu", "__Libraries\StellaOps.Concelier.Connector.Ru.Bdu\StellaOps.Concelier.Connector.Ru.Bdu.csproj", "{40591EC3-23C6-4E74-8280-35153641FF21}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Nkcki", "__Libraries\StellaOps.Concelier.Connector.Ru.Nkcki\StellaOps.Concelier.Connector.Ru.Nkcki.csproj", "{5646F7F2-FEDF-49D1-9053-F8E1B7892695}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.StellaOpsMirror", "__Libraries\StellaOps.Concelier.Connector.StellaOpsMirror\StellaOps.Concelier.Connector.StellaOpsMirror.csproj", "{3C877F0B-3870-452B-AA70-1F9960A4F062}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Adobe", "__Libraries\StellaOps.Concelier.Connector.Vndr.Adobe\StellaOps.Concelier.Connector.Vndr.Adobe.csproj", "{5525AD40-01DA-46DD-B331-DD032DD3C9C0}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Apple", "__Libraries\StellaOps.Concelier.Connector.Vndr.Apple\StellaOps.Concelier.Connector.Vndr.Apple.csproj", "{D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Chromium", "__Libraries\StellaOps.Concelier.Connector.Vndr.Chromium\StellaOps.Concelier.Connector.Vndr.Chromium.csproj", "{296A426A-E429-4984-8813-AA7EEE3037D5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Cisco", "__Libraries\StellaOps.Concelier.Connector.Vndr.Cisco\StellaOps.Concelier.Connector.Vndr.Cisco.csproj", "{6F1AB15F-8875-4A62-A878-842D463A3B11}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Msrc", "__Libraries\StellaOps.Concelier.Connector.Vndr.Msrc\StellaOps.Concelier.Connector.Vndr.Msrc.csproj", "{CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Oracle", "__Libraries\StellaOps.Concelier.Connector.Vndr.Oracle\StellaOps.Concelier.Connector.Vndr.Oracle.csproj", "{8EFE438F-0513-470C-909B-8A1BD62D0E98}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Vmware", "__Libraries\StellaOps.Concelier.Connector.Vndr.Vmware\StellaOps.Concelier.Connector.Vndr.Vmware.csproj", "{60712A8D-FF22-452C-8AC0-22DB33B38180}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.Json", "__Libraries\StellaOps.Concelier.Exporter.Json\StellaOps.Concelier.Exporter.Json.csproj", "{4097C3CB-7C39-478B-89C2-4D317625EBBF}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.TrivyDb", "__Libraries\StellaOps.Concelier.Exporter.TrivyDb\StellaOps.Concelier.Exporter.TrivyDb.csproj", "{935D16AC-8EBD-46E4-8D0E-934F3AE961D4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Testing", "__Libraries\StellaOps.Concelier.Testing\StellaOps.Concelier.Testing.csproj", "{0BC8276D-D726-4C8B-AB2B-122BE18F1112}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Tests", "__Tests", "{56BCE1BF-7CBA-7CE8-203D-A88051F1D642}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Acsc.Tests", "__Tests\StellaOps.Concelier.Connector.Acsc.Tests\StellaOps.Concelier.Connector.Acsc.Tests.csproj", "{654CF4EE-9EC5-464C-AF47-EE37329CD46A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cccs.Tests", "__Tests\StellaOps.Concelier.Connector.Cccs.Tests\StellaOps.Concelier.Connector.Cccs.Tests.csproj", "{BEF6FA33-E0EA-4ED2-B209-833D41607132}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertBund.Tests", "__Tests\StellaOps.Concelier.Connector.CertBund.Tests\StellaOps.Concelier.Connector.CertBund.Tests.csproj", "{B777945B-92DB-4D24-A795-5C900B6FCB92}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertCc.Tests", "__Tests\StellaOps.Concelier.Connector.CertCc.Tests\StellaOps.Concelier.Connector.CertCc.Tests.csproj", "{67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertFr.Tests", "__Tests\StellaOps.Concelier.Connector.CertFr.Tests\StellaOps.Concelier.Connector.CertFr.Tests.csproj", "{0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.CertIn.Tests", "__Tests\StellaOps.Concelier.Connector.CertIn.Tests\StellaOps.Concelier.Connector.CertIn.Tests.csproj", "{0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Common.Tests", "__Tests\StellaOps.Concelier.Connector.Common.Tests\StellaOps.Concelier.Connector.Common.Tests.csproj", "{35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Cve.Tests", "__Tests\StellaOps.Concelier.Connector.Cve.Tests\StellaOps.Concelier.Connector.Cve.Tests.csproj", "{F90FCF19-0426-4E62-93DC-835712E5B064}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Debian.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.Debian.Tests\StellaOps.Concelier.Connector.Distro.Debian.Tests.csproj", "{0E84E05F-53CE-4A6E-95F0-62EF14CBC385}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.RedHat.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.RedHat.Tests\StellaOps.Concelier.Connector.Distro.RedHat.Tests.csproj", "{7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Suse.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.Suse.Tests\StellaOps.Concelier.Connector.Distro.Suse.Tests.csproj", "{4DD7C512-5624-4C6B-B02A-7EDF58242657}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Distro.Ubuntu.Tests", "__Tests\StellaOps.Concelier.Connector.Distro.Ubuntu.Tests\StellaOps.Concelier.Connector.Distro.Ubuntu.Tests.csproj", "{98AA9471-2498-45BC-A58F-B83F4B9A8B75}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ghsa.Tests", "__Tests\StellaOps.Concelier.Connector.Ghsa.Tests\StellaOps.Concelier.Connector.Ghsa.Tests.csproj", "{7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Cisa.Tests", "__Tests\StellaOps.Concelier.Connector.Ics.Cisa.Tests\StellaOps.Concelier.Connector.Ics.Cisa.Tests.csproj", "{253BAF8F-0CF8-4D1A-B5AA-F19713099173}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ics.Kaspersky.Tests", "__Tests\StellaOps.Concelier.Connector.Ics.Kaspersky.Tests\StellaOps.Concelier.Connector.Ics.Kaspersky.Tests.csproj", "{57A423CD-4F40-4BAD-A6FC-93D494FCA51A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Jvn.Tests", "__Tests\StellaOps.Concelier.Connector.Jvn.Tests\StellaOps.Concelier.Connector.Jvn.Tests.csproj", "{07034F70-3E4F-49BF-A181-75443D3B3361}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kev.Tests", "__Tests\StellaOps.Concelier.Connector.Kev.Tests\StellaOps.Concelier.Connector.Kev.Tests.csproj", "{E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Kisa.Tests", "__Tests\StellaOps.Concelier.Connector.Kisa.Tests\StellaOps.Concelier.Connector.Kisa.Tests.csproj", "{9165A6AB-140D-41BC-91BC-44523D1C9978}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Nvd.Tests", "__Tests\StellaOps.Concelier.Connector.Nvd.Tests\StellaOps.Concelier.Connector.Nvd.Tests.csproj", "{A35677A8-170D-4933-B2C3-314A30920766}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Osv.Tests", "__Tests\StellaOps.Concelier.Connector.Osv.Tests\StellaOps.Concelier.Connector.Osv.Tests.csproj", "{E21AD10F-87B8-4C39-BE45-B6C44CE6D841}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Bdu.Tests", "__Tests\StellaOps.Concelier.Connector.Ru.Bdu.Tests\StellaOps.Concelier.Connector.Ru.Bdu.Tests.csproj", "{1E93E173-53B1-4441-97E0-C60A3FB029D7}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Ru.Nkcki.Tests", "__Tests\StellaOps.Concelier.Connector.Ru.Nkcki.Tests\StellaOps.Concelier.Connector.Ru.Nkcki.Tests.csproj", "{92827ACC-284F-44EB-98A7-94B57BA92D27}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.StellaOpsMirror.Tests", "__Tests\StellaOps.Concelier.Connector.StellaOpsMirror.Tests\StellaOps.Concelier.Connector.StellaOpsMirror.Tests.csproj", "{1B017E4D-6F3E-42D4-9418-DA8D76BA2797}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Adobe.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Adobe.Tests\StellaOps.Concelier.Connector.Vndr.Adobe.Tests.csproj", "{45A163F4-2569-40D9-8FF6-854AF95C061E}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Apple.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Apple.Tests\StellaOps.Concelier.Connector.Vndr.Apple.Tests.csproj", "{17934A3D-6420-48F2-A528-E32A34F0FE55}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Chromium.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Chromium.Tests\StellaOps.Concelier.Connector.Vndr.Chromium.Tests.csproj", "{07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Cisco.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Cisco.Tests\StellaOps.Concelier.Connector.Vndr.Cisco.Tests.csproj", "{D485A847-B3EA-40D8-A56A-459A02C902F8}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Msrc.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Msrc.Tests\StellaOps.Concelier.Connector.Vndr.Msrc.Tests.csproj", "{0B716CE2-810A-4143-8434-4DB111E0F3E9}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Oracle.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Oracle.Tests\StellaOps.Concelier.Connector.Vndr.Oracle.Tests.csproj", "{2A75CB97-ACF1-43B2-8509-E8226000D7DC}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Connector.Vndr.Vmware.Tests", "__Tests\StellaOps.Concelier.Connector.Vndr.Vmware.Tests\StellaOps.Concelier.Connector.Vndr.Vmware.Tests.csproj", "{3AEC19B5-44F6-4717-B1A0-3A2F04F42565}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Core.Tests", "__Tests\StellaOps.Concelier.Core.Tests\StellaOps.Concelier.Core.Tests.csproj", "{1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.Json.Tests", "__Tests\StellaOps.Concelier.Exporter.Json.Tests\StellaOps.Concelier.Exporter.Json.Tests.csproj", "{258A6D13-F02C-48C6-8506-2C815EBBD1D5}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Exporter.TrivyDb.Tests", "__Tests\StellaOps.Concelier.Exporter.TrivyDb.Tests\StellaOps.Concelier.Exporter.TrivyDb.Tests.csproj", "{39F8D963-3D76-4BEC-BE7B-4AE9C9664211}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Merge.Tests", "__Tests\StellaOps.Concelier.Merge.Tests\StellaOps.Concelier.Merge.Tests.csproj", "{470793D6-A847-41E3-A15D-8D0DFE7CD9A3}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Models.Tests", "__Tests\StellaOps.Concelier.Models.Tests\StellaOps.Concelier.Models.Tests.csproj", "{2EB876DE-E940-4A7E-8E3D-804E2E6314DA}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Normalization.Tests", "__Tests\StellaOps.Concelier.Normalization.Tests\StellaOps.Concelier.Normalization.Tests.csproj", "{C4C2037E-B301-4449-96D6-C6B165752E1A}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.RawModels.Tests", "__Tests\StellaOps.Concelier.RawModels.Tests\StellaOps.Concelier.RawModels.Tests.csproj", "{7B995CBB-3D20-4509-9300-EC012C18C4B4}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Storage.Mongo.Tests", "__Tests\StellaOps.Concelier.Storage.Mongo.Tests\StellaOps.Concelier.Storage.Mongo.Tests.csproj", "{9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.WebService.Tests", "__Tests\StellaOps.Concelier.WebService.Tests\StellaOps.Concelier.WebService.Tests.csproj", "{664A2577-6DA1-42DA-A213-3253017FA4BF}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "__Analyzers", "__Analyzers", "{176B5A8A-7857-3ECD-1128-3C721BC7F5C6}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StellaOps.Concelier.Analyzers", "__Analyzers\StellaOps.Concelier.Analyzers\StellaOps.Concelier.Analyzers.csproj", "{39C1D44C-389F-4502-ADCF-E4AC359E8F8F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|Any CPU = Release|Any CPU
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x64.Build.0 = Debug|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Debug|x86.Build.0 = Debug|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x64.ActiveCfg = Release|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x64.Build.0 = Release|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x86.ActiveCfg = Release|Any CPU
+ {FB98E71B-AF9D-4593-8306-F989C2CA2BBE}.Release|x86.Build.0 = Release|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x64.Build.0 = Debug|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Debug|x86.Build.0 = Debug|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x64.ActiveCfg = Release|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x64.Build.0 = Release|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x86.ActiveCfg = Release|Any CPU
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838}.Release|x86.Build.0 = Release|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x64.Build.0 = Debug|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Debug|x86.Build.0 = Debug|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|Any CPU.Build.0 = Release|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x64.ActiveCfg = Release|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x64.Build.0 = Release|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x86.ActiveCfg = Release|Any CPU
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94}.Release|x86.Build.0 = Release|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x64.Build.0 = Debug|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Debug|x86.Build.0 = Debug|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x64.ActiveCfg = Release|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x64.Build.0 = Release|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x86.ActiveCfg = Release|Any CPU
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118}.Release|x86.Build.0 = Release|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x64.Build.0 = Debug|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Debug|x86.Build.0 = Debug|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x64.ActiveCfg = Release|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x64.Build.0 = Release|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x86.ActiveCfg = Release|Any CPU
+ {628700D6-97A5-4506-BC78-22E2A76C68E3}.Release|x86.Build.0 = Release|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x64.Build.0 = Debug|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Debug|x86.Build.0 = Debug|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x64.ActiveCfg = Release|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x64.Build.0 = Release|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x86.ActiveCfg = Release|Any CPU
+ {A3E52755-5B68-4A33-9078-893A7FEE7D4B}.Release|x86.Build.0 = Release|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x64.Build.0 = Debug|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Debug|x86.Build.0 = Debug|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Release|x64.ActiveCfg = Release|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Release|x64.Build.0 = Release|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Release|x86.ActiveCfg = Release|Any CPU
+ {7B48F422-65E3-464B-B029-0766207035EB}.Release|x86.Build.0 = Release|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x64.Build.0 = Debug|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Debug|x86.Build.0 = Debug|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x64.ActiveCfg = Release|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x64.Build.0 = Release|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x86.ActiveCfg = Release|Any CPU
+ {A6802486-A8D3-4623-8D81-04ED23F9D312}.Release|x86.Build.0 = Release|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x64.Build.0 = Debug|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Debug|x86.Build.0 = Debug|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x64.ActiveCfg = Release|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x64.Build.0 = Release|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x86.ActiveCfg = Release|Any CPU
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5}.Release|x86.Build.0 = Release|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x64.Build.0 = Debug|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Debug|x86.Build.0 = Debug|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x64.ActiveCfg = Release|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x64.Build.0 = Release|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x86.ActiveCfg = Release|Any CPU
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB}.Release|x86.Build.0 = Release|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x64.Build.0 = Debug|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Debug|x86.Build.0 = Debug|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x64.ActiveCfg = Release|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x64.Build.0 = Release|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x86.ActiveCfg = Release|Any CPU
+ {7760219F-6C19-4B61-9015-73BB02005C0B}.Release|x86.Build.0 = Release|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x64.Build.0 = Debug|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Debug|x86.Build.0 = Debug|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x64.ActiveCfg = Release|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x64.Build.0 = Release|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x86.ActiveCfg = Release|Any CPU
+ {EDD39EE5-8341-4BB0-9C30-D829D97C1E65}.Release|x86.Build.0 = Release|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x64.Build.0 = Debug|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Debug|x86.Build.0 = Debug|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|Any CPU.Build.0 = Release|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x64.ActiveCfg = Release|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x64.Build.0 = Release|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x86.ActiveCfg = Release|Any CPU
+ {80E7B08C-2916-4540-A34B-CB581EEEA202}.Release|x86.Build.0 = Release|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x64.Build.0 = Debug|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Debug|x86.Build.0 = Debug|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x64.ActiveCfg = Release|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x64.Build.0 = Release|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x86.ActiveCfg = Release|Any CPU
+ {5B04974C-EC04-446E-83C1-EF9686433586}.Release|x86.Build.0 = Release|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x64.Build.0 = Debug|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Debug|x86.Build.0 = Debug|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x64.ActiveCfg = Release|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x64.Build.0 = Release|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x86.ActiveCfg = Release|Any CPU
+ {1282AA12-C27D-4F85-B534-785FEFF52D5F}.Release|x86.Build.0 = Release|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x64.Build.0 = Debug|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Debug|x86.Build.0 = Debug|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x64.ActiveCfg = Release|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x64.Build.0 = Release|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x86.ActiveCfg = Release|Any CPU
+ {C4EF36C5-AE69-4781-96A5-FB9CCFBBE6CB}.Release|x86.Build.0 = Release|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x64.Build.0 = Debug|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Debug|x86.Build.0 = Debug|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x64.ActiveCfg = Release|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x64.Build.0 = Release|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x86.ActiveCfg = Release|Any CPU
+ {A488C9CC-A6CF-46B9-AAB7-F9284FF191D9}.Release|x86.Build.0 = Release|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x64.Build.0 = Debug|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Debug|x86.Build.0 = Debug|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x64.ActiveCfg = Release|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x64.Build.0 = Release|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x86.ActiveCfg = Release|Any CPU
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998}.Release|x86.Build.0 = Release|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x64.Build.0 = Debug|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Debug|x86.Build.0 = Debug|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x64.ActiveCfg = Release|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x64.Build.0 = Release|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x86.ActiveCfg = Release|Any CPU
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4}.Release|x86.Build.0 = Release|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x64.Build.0 = Debug|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Debug|x86.Build.0 = Debug|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x64.ActiveCfg = Release|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x64.Build.0 = Release|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x86.ActiveCfg = Release|Any CPU
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6}.Release|x86.Build.0 = Release|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x64.Build.0 = Debug|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Debug|x86.Build.0 = Debug|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x64.ActiveCfg = Release|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x64.Build.0 = Release|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x86.ActiveCfg = Release|Any CPU
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8}.Release|x86.Build.0 = Release|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x64.Build.0 = Debug|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Debug|x86.Build.0 = Debug|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|Any CPU.Build.0 = Release|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x64.ActiveCfg = Release|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x64.Build.0 = Release|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x86.ActiveCfg = Release|Any CPU
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE}.Release|x86.Build.0 = Release|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x64.Build.0 = Debug|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Debug|x86.Build.0 = Debug|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x64.ActiveCfg = Release|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x64.Build.0 = Release|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x86.ActiveCfg = Release|Any CPU
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B}.Release|x86.Build.0 = Release|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x64.Build.0 = Debug|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Debug|x86.Build.0 = Debug|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|Any CPU.Build.0 = Release|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x64.ActiveCfg = Release|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x64.Build.0 = Release|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x86.ActiveCfg = Release|Any CPU
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517}.Release|x86.Build.0 = Release|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x64.Build.0 = Debug|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Debug|x86.Build.0 = Debug|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x64.ActiveCfg = Release|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x64.Build.0 = Release|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x86.ActiveCfg = Release|Any CPU
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6}.Release|x86.Build.0 = Release|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x64.Build.0 = Debug|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Debug|x86.Build.0 = Debug|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x64.ActiveCfg = Release|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x64.Build.0 = Release|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x86.ActiveCfg = Release|Any CPU
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466}.Release|x86.Build.0 = Release|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x64.Build.0 = Debug|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Debug|x86.Build.0 = Debug|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x64.ActiveCfg = Release|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x64.Build.0 = Release|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x86.ActiveCfg = Release|Any CPU
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762}.Release|x86.Build.0 = Release|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x64.Build.0 = Debug|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Debug|x86.Build.0 = Debug|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x64.ActiveCfg = Release|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x64.Build.0 = Release|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x86.ActiveCfg = Release|Any CPU
+ {2975AE79-F23D-43D6-B075-6659AB6AE105}.Release|x86.Build.0 = Release|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x64.Build.0 = Debug|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Debug|x86.Build.0 = Debug|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|Any CPU.Build.0 = Release|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x64.ActiveCfg = Release|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x64.Build.0 = Release|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x86.ActiveCfg = Release|Any CPU
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744}.Release|x86.Build.0 = Release|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x64.Build.0 = Debug|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Debug|x86.Build.0 = Debug|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x64.ActiveCfg = Release|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x64.Build.0 = Release|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x86.ActiveCfg = Release|Any CPU
+ {D4824290-3F8A-47BD-A368-F63BE593546B}.Release|x86.Build.0 = Release|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x64.Build.0 = Debug|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Debug|x86.Build.0 = Debug|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x64.ActiveCfg = Release|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x64.Build.0 = Release|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x86.ActiveCfg = Release|Any CPU
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF}.Release|x86.Build.0 = Release|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x64.Build.0 = Debug|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Debug|x86.Build.0 = Debug|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x64.ActiveCfg = Release|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x64.Build.0 = Release|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x86.ActiveCfg = Release|Any CPU
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C}.Release|x86.Build.0 = Release|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x64.Build.0 = Debug|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Debug|x86.Build.0 = Debug|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x64.ActiveCfg = Release|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x64.Build.0 = Release|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x86.ActiveCfg = Release|Any CPU
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA}.Release|x86.Build.0 = Release|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x64.Build.0 = Debug|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Debug|x86.Build.0 = Debug|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x64.ActiveCfg = Release|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x64.Build.0 = Release|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x86.ActiveCfg = Release|Any CPU
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF}.Release|x86.Build.0 = Release|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x64.Build.0 = Debug|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Debug|x86.Build.0 = Debug|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x64.ActiveCfg = Release|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x64.Build.0 = Release|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x86.ActiveCfg = Release|Any CPU
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9}.Release|x86.Build.0 = Release|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x64.Build.0 = Debug|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Debug|x86.Build.0 = Debug|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x64.ActiveCfg = Release|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x64.Build.0 = Release|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x86.ActiveCfg = Release|Any CPU
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918}.Release|x86.Build.0 = Release|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x64.Build.0 = Debug|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Debug|x86.Build.0 = Debug|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Release|Any CPU.Build.0 = Release|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x64.ActiveCfg = Release|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x64.Build.0 = Release|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x86.ActiveCfg = Release|Any CPU
+ {40591EC3-23C6-4E74-8280-35153641FF21}.Release|x86.Build.0 = Release|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x64.Build.0 = Debug|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Debug|x86.Build.0 = Debug|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x64.ActiveCfg = Release|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x64.Build.0 = Release|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x86.ActiveCfg = Release|Any CPU
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695}.Release|x86.Build.0 = Release|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x64.Build.0 = Debug|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Debug|x86.Build.0 = Debug|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x64.ActiveCfg = Release|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x64.Build.0 = Release|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x86.ActiveCfg = Release|Any CPU
+ {3C877F0B-3870-452B-AA70-1F9960A4F062}.Release|x86.Build.0 = Release|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x64.Build.0 = Debug|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Debug|x86.Build.0 = Debug|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x64.ActiveCfg = Release|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x64.Build.0 = Release|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x86.ActiveCfg = Release|Any CPU
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0}.Release|x86.Build.0 = Release|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x64.Build.0 = Debug|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Debug|x86.Build.0 = Debug|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x64.ActiveCfg = Release|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x64.Build.0 = Release|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x86.ActiveCfg = Release|Any CPU
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77}.Release|x86.Build.0 = Release|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x64.Build.0 = Debug|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Debug|x86.Build.0 = Debug|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x64.ActiveCfg = Release|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x64.Build.0 = Release|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x86.ActiveCfg = Release|Any CPU
+ {296A426A-E429-4984-8813-AA7EEE3037D5}.Release|x86.Build.0 = Release|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x64.Build.0 = Debug|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Debug|x86.Build.0 = Debug|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|Any CPU.Build.0 = Release|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x64.ActiveCfg = Release|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x64.Build.0 = Release|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x86.ActiveCfg = Release|Any CPU
+ {6F1AB15F-8875-4A62-A878-842D463A3B11}.Release|x86.Build.0 = Release|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x64.Build.0 = Debug|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Debug|x86.Build.0 = Debug|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|Any CPU.Build.0 = Release|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x64.ActiveCfg = Release|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x64.Build.0 = Release|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x86.ActiveCfg = Release|Any CPU
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2}.Release|x86.Build.0 = Release|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x64.Build.0 = Debug|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Debug|x86.Build.0 = Debug|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|Any CPU.Build.0 = Release|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x64.ActiveCfg = Release|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x64.Build.0 = Release|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x86.ActiveCfg = Release|Any CPU
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98}.Release|x86.Build.0 = Release|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x64.Build.0 = Debug|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Debug|x86.Build.0 = Debug|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|Any CPU.Build.0 = Release|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x64.ActiveCfg = Release|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x64.Build.0 = Release|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x86.ActiveCfg = Release|Any CPU
+ {60712A8D-FF22-452C-8AC0-22DB33B38180}.Release|x86.Build.0 = Release|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x64.Build.0 = Debug|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Debug|x86.Build.0 = Debug|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x64.ActiveCfg = Release|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x64.Build.0 = Release|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x86.ActiveCfg = Release|Any CPU
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF}.Release|x86.Build.0 = Release|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x64.Build.0 = Debug|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Debug|x86.Build.0 = Debug|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x64.ActiveCfg = Release|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x64.Build.0 = Release|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x86.ActiveCfg = Release|Any CPU
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4}.Release|x86.Build.0 = Release|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x64.Build.0 = Debug|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Debug|x86.Build.0 = Debug|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x64.ActiveCfg = Release|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x64.Build.0 = Release|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x86.ActiveCfg = Release|Any CPU
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112}.Release|x86.Build.0 = Release|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x64.Build.0 = Debug|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Debug|x86.Build.0 = Debug|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x64.ActiveCfg = Release|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x64.Build.0 = Release|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x86.ActiveCfg = Release|Any CPU
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A}.Release|x86.Build.0 = Release|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x64.Build.0 = Debug|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Debug|x86.Build.0 = Debug|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|Any CPU.Build.0 = Release|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x64.ActiveCfg = Release|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x64.Build.0 = Release|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x86.ActiveCfg = Release|Any CPU
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132}.Release|x86.Build.0 = Release|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x64.Build.0 = Debug|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Debug|x86.Build.0 = Debug|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|Any CPU.Build.0 = Release|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x64.ActiveCfg = Release|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x64.Build.0 = Release|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x86.ActiveCfg = Release|Any CPU
+ {B777945B-92DB-4D24-A795-5C900B6FCB92}.Release|x86.Build.0 = Release|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x64.Build.0 = Debug|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Debug|x86.Build.0 = Debug|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x64.ActiveCfg = Release|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x64.Build.0 = Release|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x86.ActiveCfg = Release|Any CPU
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A}.Release|x86.Build.0 = Release|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x64.Build.0 = Debug|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Debug|x86.Build.0 = Debug|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x64.ActiveCfg = Release|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x64.Build.0 = Release|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x86.ActiveCfg = Release|Any CPU
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84}.Release|x86.Build.0 = Release|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x64.Build.0 = Debug|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Debug|x86.Build.0 = Debug|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x64.ActiveCfg = Release|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x64.Build.0 = Release|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x86.ActiveCfg = Release|Any CPU
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864}.Release|x86.Build.0 = Release|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x64.Build.0 = Debug|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Debug|x86.Build.0 = Debug|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|Any CPU.Build.0 = Release|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x64.ActiveCfg = Release|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x64.Build.0 = Release|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x86.ActiveCfg = Release|Any CPU
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B}.Release|x86.Build.0 = Release|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x64.Build.0 = Debug|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Debug|x86.Build.0 = Debug|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|Any CPU.Build.0 = Release|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x64.ActiveCfg = Release|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x64.Build.0 = Release|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x86.ActiveCfg = Release|Any CPU
+ {F90FCF19-0426-4E62-93DC-835712E5B064}.Release|x86.Build.0 = Release|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x64.Build.0 = Debug|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Debug|x86.Build.0 = Debug|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x64.ActiveCfg = Release|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x64.Build.0 = Release|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x86.ActiveCfg = Release|Any CPU
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385}.Release|x86.Build.0 = Release|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x64.Build.0 = Debug|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Debug|x86.Build.0 = Debug|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x64.ActiveCfg = Release|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x64.Build.0 = Release|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x86.ActiveCfg = Release|Any CPU
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4}.Release|x86.Build.0 = Release|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x64.Build.0 = Debug|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Debug|x86.Build.0 = Debug|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x64.ActiveCfg = Release|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x64.Build.0 = Release|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x86.ActiveCfg = Release|Any CPU
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657}.Release|x86.Build.0 = Release|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x64.Build.0 = Debug|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Debug|x86.Build.0 = Debug|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|Any CPU.Build.0 = Release|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x64.ActiveCfg = Release|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x64.Build.0 = Release|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x86.ActiveCfg = Release|Any CPU
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75}.Release|x86.Build.0 = Release|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x64.Build.0 = Debug|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Debug|x86.Build.0 = Debug|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x64.ActiveCfg = Release|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x64.Build.0 = Release|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x86.ActiveCfg = Release|Any CPU
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40}.Release|x86.Build.0 = Release|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x64.Build.0 = Debug|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Debug|x86.Build.0 = Debug|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|Any CPU.Build.0 = Release|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x64.ActiveCfg = Release|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x64.Build.0 = Release|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x86.ActiveCfg = Release|Any CPU
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173}.Release|x86.Build.0 = Release|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x64.Build.0 = Debug|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Debug|x86.Build.0 = Debug|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x64.ActiveCfg = Release|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x64.Build.0 = Release|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x86.ActiveCfg = Release|Any CPU
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A}.Release|x86.Build.0 = Release|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x64.Build.0 = Debug|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Debug|x86.Build.0 = Debug|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|Any CPU.Build.0 = Release|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x64.ActiveCfg = Release|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x64.Build.0 = Release|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x86.ActiveCfg = Release|Any CPU
+ {07034F70-3E4F-49BF-A181-75443D3B3361}.Release|x86.Build.0 = Release|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x64.Build.0 = Debug|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Debug|x86.Build.0 = Debug|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x64.ActiveCfg = Release|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x64.Build.0 = Release|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x86.ActiveCfg = Release|Any CPU
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1}.Release|x86.Build.0 = Release|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x64.Build.0 = Debug|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Debug|x86.Build.0 = Debug|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x64.ActiveCfg = Release|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x64.Build.0 = Release|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x86.ActiveCfg = Release|Any CPU
+ {9165A6AB-140D-41BC-91BC-44523D1C9978}.Release|x86.Build.0 = Release|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x64.Build.0 = Debug|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Debug|x86.Build.0 = Debug|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Release|Any CPU.Build.0 = Release|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Release|x64.ActiveCfg = Release|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Release|x64.Build.0 = Release|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Release|x86.ActiveCfg = Release|Any CPU
+ {A35677A8-170D-4933-B2C3-314A30920766}.Release|x86.Build.0 = Release|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x64.Build.0 = Debug|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Debug|x86.Build.0 = Debug|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|Any CPU.Build.0 = Release|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x64.ActiveCfg = Release|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x64.Build.0 = Release|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x86.ActiveCfg = Release|Any CPU
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841}.Release|x86.Build.0 = Release|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x64.Build.0 = Debug|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Debug|x86.Build.0 = Debug|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x64.ActiveCfg = Release|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x64.Build.0 = Release|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x86.ActiveCfg = Release|Any CPU
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7}.Release|x86.Build.0 = Release|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x64.Build.0 = Debug|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Debug|x86.Build.0 = Debug|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|Any CPU.Build.0 = Release|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x64.ActiveCfg = Release|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x64.Build.0 = Release|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x86.ActiveCfg = Release|Any CPU
+ {92827ACC-284F-44EB-98A7-94B57BA92D27}.Release|x86.Build.0 = Release|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x64.Build.0 = Debug|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Debug|x86.Build.0 = Debug|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x64.ActiveCfg = Release|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x64.Build.0 = Release|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x86.ActiveCfg = Release|Any CPU
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797}.Release|x86.Build.0 = Release|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x64.Build.0 = Debug|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Debug|x86.Build.0 = Debug|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|Any CPU.Build.0 = Release|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x64.ActiveCfg = Release|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x64.Build.0 = Release|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x86.ActiveCfg = Release|Any CPU
+ {45A163F4-2569-40D9-8FF6-854AF95C061E}.Release|x86.Build.0 = Release|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x64.Build.0 = Debug|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Debug|x86.Build.0 = Debug|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|Any CPU.Build.0 = Release|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x64.ActiveCfg = Release|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x64.Build.0 = Release|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x86.ActiveCfg = Release|Any CPU
+ {17934A3D-6420-48F2-A528-E32A34F0FE55}.Release|x86.Build.0 = Release|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x64.Build.0 = Debug|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Debug|x86.Build.0 = Debug|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|Any CPU.Build.0 = Release|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x64.ActiveCfg = Release|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x64.Build.0 = Release|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x86.ActiveCfg = Release|Any CPU
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D}.Release|x86.Build.0 = Release|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x64.Build.0 = Debug|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Debug|x86.Build.0 = Debug|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|Any CPU.Build.0 = Release|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x64.ActiveCfg = Release|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x64.Build.0 = Release|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x86.ActiveCfg = Release|Any CPU
+ {D485A847-B3EA-40D8-A56A-459A02C902F8}.Release|x86.Build.0 = Release|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x64.Build.0 = Debug|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Debug|x86.Build.0 = Debug|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|Any CPU.Build.0 = Release|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x64.ActiveCfg = Release|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x64.Build.0 = Release|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x86.ActiveCfg = Release|Any CPU
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9}.Release|x86.Build.0 = Release|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x64.Build.0 = Debug|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Debug|x86.Build.0 = Debug|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x64.ActiveCfg = Release|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x64.Build.0 = Release|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x86.ActiveCfg = Release|Any CPU
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC}.Release|x86.Build.0 = Release|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x64.Build.0 = Debug|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Debug|x86.Build.0 = Debug|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|Any CPU.Build.0 = Release|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x64.ActiveCfg = Release|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x64.Build.0 = Release|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x86.ActiveCfg = Release|Any CPU
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565}.Release|x86.Build.0 = Release|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x64.Build.0 = Debug|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Debug|x86.Build.0 = Debug|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|Any CPU.Build.0 = Release|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x64.ActiveCfg = Release|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x64.Build.0 = Release|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x86.ActiveCfg = Release|Any CPU
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691}.Release|x86.Build.0 = Release|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x64.Build.0 = Debug|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Debug|x86.Build.0 = Debug|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|Any CPU.Build.0 = Release|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x64.ActiveCfg = Release|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x64.Build.0 = Release|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x86.ActiveCfg = Release|Any CPU
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5}.Release|x86.Build.0 = Release|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x64.Build.0 = Debug|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Debug|x86.Build.0 = Debug|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|Any CPU.Build.0 = Release|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x64.ActiveCfg = Release|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x64.Build.0 = Release|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x86.ActiveCfg = Release|Any CPU
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211}.Release|x86.Build.0 = Release|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x64.Build.0 = Debug|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Debug|x86.Build.0 = Debug|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|Any CPU.Build.0 = Release|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x64.ActiveCfg = Release|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x64.Build.0 = Release|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x86.ActiveCfg = Release|Any CPU
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3}.Release|x86.Build.0 = Release|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x64.Build.0 = Debug|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Debug|x86.Build.0 = Debug|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|Any CPU.Build.0 = Release|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x64.ActiveCfg = Release|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x64.Build.0 = Release|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x86.ActiveCfg = Release|Any CPU
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA}.Release|x86.Build.0 = Release|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x64.Build.0 = Debug|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Debug|x86.Build.0 = Debug|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|Any CPU.Build.0 = Release|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x64.ActiveCfg = Release|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x64.Build.0 = Release|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x86.ActiveCfg = Release|Any CPU
+ {C4C2037E-B301-4449-96D6-C6B165752E1A}.Release|x86.Build.0 = Release|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x64.Build.0 = Debug|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Debug|x86.Build.0 = Debug|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|Any CPU.Build.0 = Release|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x64.ActiveCfg = Release|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x64.Build.0 = Release|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x86.ActiveCfg = Release|Any CPU
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4}.Release|x86.Build.0 = Release|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x64.Build.0 = Debug|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Debug|x86.Build.0 = Debug|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|Any CPU.Build.0 = Release|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x64.ActiveCfg = Release|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x64.Build.0 = Release|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x86.ActiveCfg = Release|Any CPU
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62}.Release|x86.Build.0 = Release|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x64.Build.0 = Debug|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Debug|x86.Build.0 = Debug|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|Any CPU.Build.0 = Release|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x64.ActiveCfg = Release|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x64.Build.0 = Release|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x86.ActiveCfg = Release|Any CPU
+ {664A2577-6DA1-42DA-A213-3253017FA4BF}.Release|x86.Build.0 = Release|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Debug|x64.Build.0 = Debug|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Debug|x86.Build.0 = Debug|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Release|x64.ActiveCfg = Release|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Release|x64.Build.0 = Release|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Release|x86.ActiveCfg = Release|Any CPU
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F}.Release|x86.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(NestedProjects) = preSolution
+ {D93F34C2-5E5E-4CC7-A573-4376AA525838} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {841F3EF5-7EB6-4F76-8A37-0AAFEED0DE94} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {EEC52FA0-8E78-4FCB-9454-D697F58B2118} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {628700D6-97A5-4506-BC78-22E2A76C68E3} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {C926373D-5ACB-4E62-96D5-264EF4C61BE5} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {2D68125A-0ACD-4015-A8FA-B54284B8A3CB} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {7760219F-6C19-4B61-9015-73BB02005C0B} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {F87DFC58-EE3E-4E2F-9E17-E6A6924F2998} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {30056CC9-4D34-4C2E-B60D-6D9B12DF0DF4} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {77FF9993-C811-4389-8BFE-974B4F0AB7C6} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {4FB18D5B-8D48-4E50-9608-69890B3420F8} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {585DA0F6-BD2D-4CD9-8CEC-A0A4C9E3DCFE} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {BAB3573C-C17E-436E-B3D5-F6C0E0B2825B} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {257E2D7B-EA3D-4B33-9546-7B77DA20A517} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {5C9D617D-86B6-4CAA-9981-A438DBFE8BB6} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {C827F73E-68E2-4F6A-8CEA-0425B2D2D466} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {F67EECB0-7DCC-4643-82F3-E020D72BE762} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {2975AE79-F23D-43D6-B075-6659AB6AE105} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {667ACFE7-922E-4958-99D6-DD9D7BE8E744} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {D4824290-3F8A-47BD-A368-F63BE593546B} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {B69F3D80-EACD-4A1B-80A0-0B5D7AD941AF} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {33C98234-DF04-40CE-9459-2736AAB0CF6C} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {A6D364F9-3478-4432-9EE1-F4F3DCF125EA} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {B9EDA23E-5754-48AF-8978-DBCBF75134BF} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {9208F373-EDD1-491D-AEF9-FE280B453CD9} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {EC5DE6F3-D158-4261-A4CD-AB81AE154918} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {40591EC3-23C6-4E74-8280-35153641FF21} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {5646F7F2-FEDF-49D1-9053-F8E1B7892695} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {3C877F0B-3870-452B-AA70-1F9960A4F062} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {5525AD40-01DA-46DD-B331-DD032DD3C9C0} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {D6D4DFB9-7ADC-4D10-9904-6A5AD97FFE77} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {296A426A-E429-4984-8813-AA7EEE3037D5} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {6F1AB15F-8875-4A62-A878-842D463A3B11} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {CEFF5CDF-63F2-4EE6-9B95-7DB3DC9474B2} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {8EFE438F-0513-470C-909B-8A1BD62D0E98} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {60712A8D-FF22-452C-8AC0-22DB33B38180} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {4097C3CB-7C39-478B-89C2-4D317625EBBF} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {935D16AC-8EBD-46E4-8D0E-934F3AE961D4} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {0BC8276D-D726-4C8B-AB2B-122BE18F1112} = {41F15E67-7190-CF23-3BC4-77E87134CADD}
+ {654CF4EE-9EC5-464C-AF47-EE37329CD46A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {BEF6FA33-E0EA-4ED2-B209-833D41607132} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {B777945B-92DB-4D24-A795-5C900B6FCB92} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {67B08EB0-7140-49C5-9BFA-DEA1A3A06E6A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {0EDACFF4-DD7B-4FBB-9774-21B909EA8D84} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {0E1CAB5C-649A-47B6-BFE3-E53B5F63B864} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {35DDC22F-F6C4-43A8-9E08-AD5E5CF2354B} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {F90FCF19-0426-4E62-93DC-835712E5B064} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {0E84E05F-53CE-4A6E-95F0-62EF14CBC385} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {7B55B3B3-BBD2-406B-AB7C-5FB6E29923E4} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {4DD7C512-5624-4C6B-B02A-7EDF58242657} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {98AA9471-2498-45BC-A58F-B83F4B9A8B75} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {7A3BB8C3-27CE-4FB0-996A-11C7A873AB40} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {253BAF8F-0CF8-4D1A-B5AA-F19713099173} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {57A423CD-4F40-4BAD-A6FC-93D494FCA51A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {07034F70-3E4F-49BF-A181-75443D3B3361} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {E9F3F0B8-BEE8-4FE8-8B56-40129DA1F7B1} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {9165A6AB-140D-41BC-91BC-44523D1C9978} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {A35677A8-170D-4933-B2C3-314A30920766} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {E21AD10F-87B8-4C39-BE45-B6C44CE6D841} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {1E93E173-53B1-4441-97E0-C60A3FB029D7} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {92827ACC-284F-44EB-98A7-94B57BA92D27} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {1B017E4D-6F3E-42D4-9418-DA8D76BA2797} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {45A163F4-2569-40D9-8FF6-854AF95C061E} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {17934A3D-6420-48F2-A528-E32A34F0FE55} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {07DE99DB-F550-4F85-96F1-7EDC6B4CF86D} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {D485A847-B3EA-40D8-A56A-459A02C902F8} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {0B716CE2-810A-4143-8434-4DB111E0F3E9} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {2A75CB97-ACF1-43B2-8509-E8226000D7DC} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {3AEC19B5-44F6-4717-B1A0-3A2F04F42565} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {1BB5AE2D-2F7F-4CE9-B472-A113BF85B691} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {258A6D13-F02C-48C6-8506-2C815EBBD1D5} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {39F8D963-3D76-4BEC-BE7B-4AE9C9664211} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {470793D6-A847-41E3-A15D-8D0DFE7CD9A3} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {2EB876DE-E940-4A7E-8E3D-804E2E6314DA} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {C4C2037E-B301-4449-96D6-C6B165752E1A} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {7B995CBB-3D20-4509-9300-EC012C18C4B4} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {9006A5A2-01D8-4A70-AEA7-B7B1987C4A62} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {664A2577-6DA1-42DA-A213-3253017FA4BF} = {56BCE1BF-7CBA-7CE8-203D-A88051F1D642}
+ {39C1D44C-389F-4502-ADCF-E4AC359E8F8F} = {176B5A8A-7857-3ECD-1128-3C721BC7F5C6}
+ EndGlobalSection
+EndGlobal
diff --git a/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/AnalyzerReleases.Shipped.md b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/AnalyzerReleases.Shipped.md
new file mode 100644
index 000000000..e88a78fd5
--- /dev/null
+++ b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/AnalyzerReleases.Shipped.md
@@ -0,0 +1,2 @@
+; Shipped analyzer releases
+
diff --git a/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/AnalyzerReleases.Unshipped.md b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/AnalyzerReleases.Unshipped.md
new file mode 100644
index 000000000..5c412dba8
--- /dev/null
+++ b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/AnalyzerReleases.Unshipped.md
@@ -0,0 +1,9 @@
+## Release History
+
+### Unreleased
+
+#### New Rules
+
+Rule ID | Title | Notes
+--------|-------|------
+CONCELIER0002 | Legacy merge pipeline is disabled | Flags usage of `AddMergeModule` and `AdvisoryMergeService`.
diff --git a/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/NoMergeUsageAnalyzer.cs b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/NoMergeUsageAnalyzer.cs
new file mode 100644
index 000000000..be7adbe27
--- /dev/null
+++ b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/NoMergeUsageAnalyzer.cs
@@ -0,0 +1,152 @@
+using System;
+using System.Collections.Immutable;
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Operations;
+
+namespace StellaOps.Concelier.Analyzers;
+
+///
+/// Analyzer that flags usages of the legacy merge service APIs.
+///
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+public sealed class NoMergeUsageAnalyzer : DiagnosticAnalyzer
+{
+ ///
+ /// Diagnostic identifier for legacy merge usage violations.
+ ///
+ public const string DiagnosticId = "CONCELIER0002";
+
+ private const string Category = "Usage";
+ private const string MergeExtensionType = "StellaOps.Concelier.Merge.MergeServiceCollectionExtensions";
+ private const string MergeServiceType = "StellaOps.Concelier.Merge.Services.AdvisoryMergeService";
+
+ private static readonly LocalizableString Title = "Legacy merge pipeline is disabled";
+ private static readonly LocalizableString MessageFormat = "Do not reference the legacy Concelier merge pipeline (type '{0}')";
+ private static readonly LocalizableString Description =
+ "The legacy Concelier merge service is deprecated under MERGE-LNM-21-002. "
+ + "Switch to observation/linkset APIs or guard calls behind the concelier:features:noMergeEnabled toggle.";
+
+ private static readonly DiagnosticDescriptor Rule = new(
+ DiagnosticId,
+ Title,
+ MessageFormat,
+ Category,
+ DiagnosticSeverity.Error,
+ isEnabledByDefault: true,
+ description: Description,
+ helpLinkUri: "https://stella-ops.org/docs/migration/no-merge");
+
+ ///
+ public override ImmutableArray SupportedDiagnostics => ImmutableArray.Create(Rule);
+
+ ///
+ public override void Initialize(AnalysisContext context)
+ {
+ context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
+ context.EnableConcurrentExecution();
+
+ context.RegisterOperationAction(AnalyzeInvocation, OperationKind.Invocation);
+ context.RegisterOperationAction(AnalyzeObjectCreation, OperationKind.ObjectCreation);
+ }
+
+ private static void AnalyzeInvocation(OperationAnalysisContext context)
+ {
+ if (context.Operation is not IInvocationOperation invocation)
+ {
+ return;
+ }
+
+ var targetMethod = invocation.TargetMethod;
+ if (targetMethod is null)
+ {
+ return;
+ }
+
+ if (!SymbolEquals(targetMethod.ContainingType, MergeExtensionType))
+ {
+ return;
+ }
+
+ if (!string.Equals(targetMethod.Name, "AddMergeModule", StringComparison.Ordinal))
+ {
+ return;
+ }
+
+ if (IsAllowedAssembly(context.ContainingSymbol.ContainingAssembly))
+ {
+ return;
+ }
+
+ ReportDiagnostic(context, invocation.Syntax, $"{MergeExtensionType}.{targetMethod.Name}");
+ }
+
+ private static void AnalyzeObjectCreation(OperationAnalysisContext context)
+ {
+ if (context.Operation is not IObjectCreationOperation creation)
+ {
+ return;
+ }
+
+ var createdType = creation.Type;
+ if (createdType is null || !SymbolEquals(createdType, MergeServiceType))
+ {
+ return;
+ }
+
+ if (IsAllowedAssembly(context.ContainingSymbol.ContainingAssembly))
+ {
+ return;
+ }
+
+ ReportDiagnostic(context, creation.Syntax, MergeServiceType);
+ }
+
+ private static bool SymbolEquals(ITypeSymbol? symbol, string fullName)
+ {
+ if (symbol is null)
+ {
+ return false;
+ }
+
+ var display = symbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ if (display.StartsWith("global::", StringComparison.Ordinal))
+ {
+ display = display.Substring("global::".Length);
+ }
+
+ return string.Equals(display, fullName, StringComparison.Ordinal);
+ }
+
+ private static bool IsAllowedAssembly(IAssemblySymbol? assemblySymbol)
+ {
+ if (assemblySymbol is null)
+ {
+ return false;
+ }
+
+ var assemblyName = assemblySymbol.Name;
+ if (string.IsNullOrWhiteSpace(assemblyName))
+ {
+ return false;
+ }
+
+ if (assemblyName.StartsWith("StellaOps.Concelier.Merge", StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ if (assemblyName.EndsWith(".Analyzers", StringComparison.Ordinal))
+ {
+ return true;
+ }
+
+ return false;
+ }
+
+ private static void ReportDiagnostic(OperationAnalysisContext context, SyntaxNode syntax, string targetName)
+ {
+ var diagnostic = Diagnostic.Create(Rule, syntax.GetLocation(), targetName);
+ context.ReportDiagnostic(diagnostic);
+ }
+}
diff --git a/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/StellaOps.Concelier.Analyzers.csproj b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/StellaOps.Concelier.Analyzers.csproj
new file mode 100644
index 000000000..f07260cdf
--- /dev/null
+++ b/src/Concelier/__Analyzers/StellaOps.Concelier.Analyzers/StellaOps.Concelier.Analyzers.csproj
@@ -0,0 +1,19 @@
+
+
+
+ netstandard2.0
+ StellaOps.Concelier.Analyzers
+ StellaOps.Concelier.Analyzers
+ enable
+ latest
+ false
+ true
+ true
+
+
+
+
+
+
+
+
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Core/Linksets/AdvisoryObservationFactory.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Core/Linksets/AdvisoryObservationFactory.cs
index 4732f8720..5fe8ad244 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Core/Linksets/AdvisoryObservationFactory.cs
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Core/Linksets/AdvisoryObservationFactory.cs
@@ -114,10 +114,10 @@ internal sealed class AdvisoryObservationFactory : IAdvisoryObservationFactory
private static AdvisoryObservationLinkset CreateLinkset(RawIdentifiers identifiers, RawLinkset linkset)
{
- var aliases = NormalizeAliases(identifiers, linkset);
- var purls = NormalizePackageUrls(linkset.PackageUrls);
- var cpes = NormalizeCpes(linkset.Cpes);
- var references = NormalizeReferences(linkset.References);
+ var aliases = CollectAliases(identifiers, linkset);
+ var purls = CollectValues(linkset.PackageUrls);
+ var cpes = CollectValues(linkset.Cpes);
+ var references = CollectReferences(linkset.References);
return new AdvisoryObservationLinkset(aliases, purls, cpes, references);
}
@@ -170,124 +170,91 @@ internal sealed class AdvisoryObservationFactory : IAdvisoryObservationFactory
};
}
- private static IEnumerable NormalizeAliases(RawIdentifiers identifiers, RawLinkset linkset)
- {
- var aliases = new HashSet(StringComparer.OrdinalIgnoreCase);
-
- if (LinksetNormalization.TryNormalizeAlias(identifiers.PrimaryId, out var primary))
- {
- aliases.Add(primary);
- }
-
- foreach (var alias in identifiers.Aliases)
- {
- if (LinksetNormalization.TryNormalizeAlias(alias, out var normalized))
- {
- aliases.Add(normalized);
- }
- }
-
- foreach (var alias in linkset.Aliases)
- {
- if (LinksetNormalization.TryNormalizeAlias(alias, out var normalized))
- {
- aliases.Add(normalized);
- }
- }
-
- foreach (var note in linkset.Notes)
- {
- if (!string.IsNullOrWhiteSpace(note.Value)
- && LinksetNormalization.TryNormalizeAlias(note.Value, out var normalized))
- {
- aliases.Add(normalized);
- }
- }
-
- return aliases
- .OrderBy(static value => value, StringComparer.OrdinalIgnoreCase)
- .ToImmutableArray();
- }
-
- private static IEnumerable NormalizePackageUrls(ImmutableArray packageUrls)
- {
- if (packageUrls.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var set = new HashSet(StringComparer.Ordinal);
-
- foreach (var candidate in packageUrls)
- {
- if (!LinksetNormalization.TryNormalizePackageUrl(candidate, out var normalized) || string.IsNullOrEmpty(normalized))
- {
- continue;
- }
-
- set.Add(normalized);
- }
-
- return set
- .OrderBy(static value => value, StringComparer.Ordinal)
- .ToImmutableArray();
- }
-
- private static IEnumerable NormalizeCpes(ImmutableArray cpes)
- {
- if (cpes.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var set = new HashSet(StringComparer.Ordinal);
-
- foreach (var cpe in cpes)
- {
- if (!LinksetNormalization.TryNormalizeCpe(cpe, out var normalized) || string.IsNullOrEmpty(normalized))
- {
- continue;
- }
-
- set.Add(normalized);
- }
-
- return set
- .OrderBy(static value => value, StringComparer.Ordinal)
- .ToImmutableArray();
- }
-
- private static IEnumerable NormalizeReferences(ImmutableArray references)
- {
- if (references.IsDefaultOrEmpty)
- {
- return ImmutableArray.Empty;
- }
-
- var seen = new HashSet(StringComparer.OrdinalIgnoreCase);
- var list = new List();
-
- foreach (var reference in references)
- {
- var normalized = LinksetNormalization.TryCreateReference(reference.Type, reference.Url);
- if (normalized is null)
- {
- continue;
- }
-
- if (!seen.Add(normalized.Url))
- {
- continue;
- }
-
- list.Add(normalized);
- }
-
- return list
- .OrderBy(static reference => reference.Type, StringComparer.Ordinal)
- .ThenBy(static reference => reference.Url, StringComparer.Ordinal)
- .ToImmutableArray();
- }
+ private static IEnumerable CollectAliases(RawIdentifiers identifiers, RawLinkset linkset)
+ {
+ var results = new List();
+
+ AddAlias(results, identifiers.PrimaryId);
+ AddRange(results, identifiers.Aliases);
+ AddRange(results, linkset.Aliases);
+
+ foreach (var note in linkset.Notes)
+ {
+ if (string.IsNullOrWhiteSpace(note.Value))
+ {
+ continue;
+ }
+
+ results.Add(note.Value.Trim());
+ }
+
+ return results;
+
+ static void AddAlias(ICollection target, string? value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return;
+ }
+
+ target.Add(value.Trim());
+ }
+
+ static void AddRange(ICollection target, ImmutableArray values)
+ {
+ if (values.IsDefaultOrEmpty)
+ {
+ return;
+ }
+
+ foreach (var value in values)
+ {
+ AddAlias(target, value);
+ }
+ }
+ }
+
+ private static IEnumerable CollectValues(ImmutableArray values)
+ {
+ if (values.IsDefaultOrEmpty)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ var list = new List(values.Length);
+ foreach (var value in values)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ continue;
+ }
+
+ list.Add(value.Trim());
+ }
+
+ return list;
+ }
+
+ private static IEnumerable CollectReferences(ImmutableArray references)
+ {
+ if (references.IsDefaultOrEmpty)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ var list = new List(references.Length);
+ foreach (var reference in references)
+ {
+ if (string.IsNullOrWhiteSpace(reference.Type) || string.IsNullOrWhiteSpace(reference.Url))
+ {
+ continue;
+ }
+
+ list.Add(new AdvisoryObservationReference(reference.Type.Trim(), reference.Url.Trim()));
+ }
+
+ return list;
+ }
private static ImmutableDictionary CreateAttributes(AdvisoryRawDocument rawDocument)
{
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md b/src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md
index 69a088148..066975d03 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Core/TASKS.md
@@ -9,7 +9,7 @@
> Docs alignment (2025-10-26): Linkset expectations detailed in AOC reference §4 and policy-engine architecture §2.1.
> 2025-10-28: Advisory raw ingestion now strips client-supplied supersedes hints, logs ignored pointers, and surfaces repository-supplied supersedes identifiers; service tests cover duplicate handling and append-only semantics.
> Docs alignment (2025-10-26): Deployment guide + observability guide describe supersedes metrics; ensure implementation emits `aoc_violation_total` on failure.
-| CONCELIER-CORE-AOC-19-004 `Remove ingestion normalization` | DOING (2025-10-28) | Concelier Core Guild | CONCELIER-CORE-AOC-19-002, POLICY-AOC-19-003 | Strip normalization/dedup/severity logic from ingestion pipelines, delegate derived computations to Policy Engine, and update exporters/tests to consume raw documents only.
2025-10-29 19:05Z: Audit completed for `AdvisoryRawService`/Mongo repo to confirm alias order/dedup removal persists; identified remaining normalization in observation/linkset factory that will be revised to surface raw duplicates for Policy ingestion. Change sketch + regression matrix drafted under `docs/dev/aoc-normalization-removal-notes.md` (pending commit).
2025-10-31 20:45Z: Added raw linkset projection to observations/storage, exposing canonical+raw views, refreshed fixtures/tests, and documented behaviour in models/doc factory.
2025-10-31 21:10Z: Coordinated with Policy Engine (POLICY-ENGINE-20-003) on adoption timeline; backfill + consumer readiness tracked in `docs/dev/raw-linkset-backfill-plan.md`. |
+| CONCELIER-CORE-AOC-19-004 `Remove ingestion normalization` | DOING (2025-10-28) | Concelier Core Guild | CONCELIER-CORE-AOC-19-002, POLICY-AOC-19-003 | Strip normalization/dedup/severity logic from ingestion pipelines, delegate derived computations to Policy Engine, and update exporters/tests to consume raw documents only.
2025-10-29 19:05Z: Audit completed for `AdvisoryRawService`/Mongo repo to confirm alias order/dedup removal persists; identified remaining normalization in observation/linkset factory that will be revised to surface raw duplicates for Policy ingestion. Change sketch + regression matrix drafted under `docs/dev/aoc-normalization-removal-notes.md` (pending commit).
2025-10-31 20:45Z: Added raw linkset projection to observations/storage, exposing canonical+raw views, refreshed fixtures/tests, and documented behaviour in models/doc factory.
2025-10-31 21:10Z: Coordinated with Policy Engine (POLICY-ENGINE-20-003) on adoption timeline; backfill + consumer readiness tracked in `docs/dev/raw-linkset-backfill-plan.md`.
2025-11-05 14:25Z: Resuming to document merge-dependent normalization paths and prepare implementation notes for `noMergeEnabled` gating before code changes land.
2025-11-05 19:20Z: Observation factory/linkset now preserve upstream ordering + duplicates; canonicalisation responsibility shifts to downstream consumers with refreshed unit coverage.
2025-11-06 16:10Z: Updated AOC reference/backfill docs with raw vs canonical guidance and cross-linked analyzer guardrails. |
> Docs alignment (2025-10-26): Architecture overview emphasises policy-only derivation; coordinate with Policy Engine guild for rollout.
> 2025-10-29: `AdvisoryRawService` now preserves upstream alias/linkset ordering (trim-only) and updated AOC documentation reflects the behaviour; follow-up to ensure policy consumers handle duplicates remains open.
| CONCELIER-CORE-AOC-19-013 `Authority tenant scope smoke coverage` | TODO | Concelier Core Guild | AUTH-AOC-19-002 | Extend Concelier smoke/e2e fixtures to configure `requiredTenants` and assert cross-tenant rejection with updated Authority tokens. | Coordinate deliverable so Authority docs (`AUTH-AOC-19-003`) can close once tests are in place. |
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Jobs/MergeReconcileJob.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Jobs/MergeReconcileJob.cs
index fa7479c66..7dc22ae0c 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Jobs/MergeReconcileJob.cs
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Jobs/MergeReconcileJob.cs
@@ -5,9 +5,10 @@ using Microsoft.Extensions.Logging;
using StellaOps.Concelier.Core.Jobs;
using StellaOps.Concelier.Merge.Services;
-namespace StellaOps.Concelier.Merge.Jobs;
-
-public sealed class MergeReconcileJob : IJob
+namespace StellaOps.Concelier.Merge.Jobs;
+
+[Obsolete("MergeReconcileJob is deprecated; Link-Not-Merge supersedes merge scheduling. Disable via concelier:features:noMergeEnabled. Tracking MERGE-LNM-21-002.", DiagnosticId = "CONCELIER0001", UrlFormat = "https://stella-ops.org/docs/migration/no-merge")]
+public sealed class MergeReconcileJob : IJob
{
private readonly AdvisoryMergeService _mergeService;
private readonly ILogger _logger;
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/MergeServiceCollectionExtensions.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/MergeServiceCollectionExtensions.cs
index eb120c5c6..3a4dd0ac0 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/MergeServiceCollectionExtensions.cs
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/MergeServiceCollectionExtensions.cs
@@ -1,15 +1,17 @@
+using System;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Logging;
using StellaOps.Concelier.Core;
-using StellaOps.Concelier.Merge.Jobs;
+using StellaOps.Concelier.Merge.Jobs;
using StellaOps.Concelier.Merge.Options;
using StellaOps.Concelier.Merge.Services;
-namespace StellaOps.Concelier.Merge;
-
-public static class MergeServiceCollectionExtensions
+namespace StellaOps.Concelier.Merge;
+
+[Obsolete("Legacy merge module is deprecated; prefer Link-Not-Merge linkset pipelines. Track MERGE-LNM-21-002 and set concelier:features:noMergeEnabled=true to disable registration.", DiagnosticId = "CONCELIER0001", UrlFormat = "https://stella-ops.org/docs/migration/no-merge")]
+public static class MergeServiceCollectionExtensions
{
public static IServiceCollection AddMergeModule(this IServiceCollection services, IConfiguration configuration)
{
@@ -34,10 +36,12 @@ public static class MergeServiceCollectionExtensions
return new AdvisoryPrecedenceMerger(resolver, options, timeProvider, logger);
});
- services.TryAddSingleton();
- services.TryAddSingleton();
- services.AddTransient();
-
- return services;
- }
-}
+#pragma warning disable CS0618 // Legacy merge services are marked obsolete.
+ services.TryAddSingleton();
+ services.TryAddSingleton();
+ services.AddTransient();
+#pragma warning restore CS0618
+
+ return services;
+ }
+}
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Services/AdvisoryMergeService.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Services/AdvisoryMergeService.cs
index f697b0830..b052a2d4a 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Services/AdvisoryMergeService.cs
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/Services/AdvisoryMergeService.cs
@@ -14,9 +14,10 @@ using StellaOps.Concelier.Storage.Mongo.Aliases;
using StellaOps.Concelier.Storage.Mongo.MergeEvents;
using System.Text.Json;
-namespace StellaOps.Concelier.Merge.Services;
-
-public sealed class AdvisoryMergeService
+namespace StellaOps.Concelier.Merge.Services;
+
+[Obsolete("AdvisoryMergeService is deprecated. Transition callers to Link-Not-Merge observation/linkset APIs (MERGE-LNM-21-002) and enable concelier:features:noMergeEnabled when ready.", DiagnosticId = "CONCELIER0001", UrlFormat = "https://stella-ops.org/docs/migration/no-merge")]
+public sealed class AdvisoryMergeService
{
private static readonly Meter MergeMeter = new("StellaOps.Concelier.Merge");
private static readonly Counter AliasCollisionCounter = MergeMeter.CreateCounter(
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md
index 48f7de9b3..aac565ff0 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Merge/TASKS.md
@@ -10,6 +10,6 @@
| Task | Owner(s) | Depends on | Notes |
|---|---|---|---|
|MERGE-LNM-21-001 Migration plan authoring|BE-Merge, Architecture Guild|CONCELIER-LNM-21-101|**DONE (2025-11-03)** – Authored `docs/migration/no-merge.md` with rollout phases, backfill/validation checklists, rollback guidance, and ownership matrix for the Link-Not-Merge cutover.|
-|MERGE-LNM-21-002 Merge service deprecation|BE-Merge|MERGE-LNM-21-001|**DOING (2025-11-03)** – Auditing service registrations, DI bindings, and tests consuming `AdvisoryMergeService`; drafting deprecation plan and analyzer scope prior to code removal.|
+|MERGE-LNM-21-002 Merge service deprecation|BE-Merge|MERGE-LNM-21-001|**DOING (2025-11-03)** – Auditing service registrations, DI bindings, and tests consuming `AdvisoryMergeService`; drafting deprecation plan and analyzer scope prior to code removal.
2025-11-05 14:42Z: Implementing `concelier:features:noMergeEnabled` gate, merge job allowlist checks, `[Obsolete]` markings, and analyzer scaffolding to steer consumers toward linkset APIs.
2025-11-06 16:10Z: Introduced Roslyn analyzer (`CONCELIER0002`) referenced by Concelier WebService + tests, documented suppression guidance, and updated migration playbook.|
> 2025-11-03: Catalogued call sites (WebService Program `AddMergeModule`, built-in job registration `merge:reconcile`, `MergeReconcileJob`) and confirmed unit tests are the only direct `MergeAsync` callers; next step is to define analyzer + replacement observability coverage.
|MERGE-LNM-21-003 Determinism/test updates|QA Guild, BE-Merge|MERGE-LNM-21-002|Replace merge determinism suites with observation/linkset regression tests verifying no data mutation and conflicts remain visible.|
diff --git a/src/Concelier/__Libraries/StellaOps.Concelier.Models/Observations/AdvisoryObservation.cs b/src/Concelier/__Libraries/StellaOps.Concelier.Models/Observations/AdvisoryObservation.cs
index d09acac69..3aaab89ea 100644
--- a/src/Concelier/__Libraries/StellaOps.Concelier.Models/Observations/AdvisoryObservation.cs
+++ b/src/Concelier/__Libraries/StellaOps.Concelier.Models/Observations/AdvisoryObservation.cs
@@ -280,57 +280,60 @@ public sealed record AdvisoryObservationLinkset
IEnumerable? cpes,
IEnumerable? references)
{
- Aliases = NormalizeStringSet(aliases, toLower: true);
- Purls = NormalizeStringSet(purls);
- Cpes = NormalizeStringSet(cpes);
- References = NormalizeReferences(references);
- }
+ Aliases = ToImmutableArray(aliases);
+ Purls = ToImmutableArray(purls);
+ Cpes = ToImmutableArray(cpes);
+ References = ToImmutableReferences(references);
+ }
+
+ public ImmutableArray Aliases { get; }
+
+ public ImmutableArray Purls { get; }
- public ImmutableArray Aliases { get; }
-
- public ImmutableArray Purls { get; }
-
- public ImmutableArray Cpes { get; }
-
- public ImmutableArray References { get; }
-
- private static ImmutableArray NormalizeStringSet(IEnumerable? values, bool toLower = false)
- {
- if (values is null)
- {
- return ImmutableArray.Empty;
- }
-
- var list = new List();
- foreach (var value in values)
- {
- var trimmed = Validation.TrimToNull(value);
- if (trimmed is null)
- {
- continue;
- }
-
- list.Add(toLower ? trimmed.ToLowerInvariant() : trimmed);
- }
-
- return list
- .Distinct(StringComparer.Ordinal)
- .OrderBy(static v => v, StringComparer.Ordinal)
- .ToImmutableArray();
- }
-
- private static ImmutableArray NormalizeReferences(IEnumerable? references)
- {
- if (references is null)
- {
- return ImmutableArray.Empty;
- }
-
- return references
- .Where(static reference => reference is not null)
- .Distinct()
- .OrderBy(static reference => reference.Type, StringComparer.Ordinal)
- .ThenBy(static reference => reference.Url, StringComparer.Ordinal)
- .ToImmutableArray();
- }
-}
+ public ImmutableArray Cpes { get; }
+
+ public ImmutableArray References { get; }
+
+ private static ImmutableArray ToImmutableArray(IEnumerable? values)
+ {
+ if (values is null)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ var builder = ImmutableArray.CreateBuilder();
+ foreach (var value in values)
+ {
+ var trimmed = Validation.TrimToNull(value);
+ if (trimmed is null)
+ {
+ continue;
+ }
+
+ builder.Add(trimmed);
+ }
+
+ return builder.Count == 0 ? ImmutableArray.Empty : builder.ToImmutable();
+ }
+
+ private static ImmutableArray ToImmutableReferences(IEnumerable? references)
+ {
+ if (references is null)
+ {
+ return ImmutableArray.Empty;
+ }
+
+ var builder = ImmutableArray.CreateBuilder();
+ foreach (var reference in references)
+ {
+ if (reference is null)
+ {
+ continue;
+ }
+
+ builder.Add(reference);
+ }
+
+ return builder.Count == 0 ? ImmutableArray.Empty : builder.ToImmutable();
+ }
+}
diff --git a/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Linksets/AdvisoryObservationFactoryTests.cs b/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Linksets/AdvisoryObservationFactoryTests.cs
index 1500375ed..48c03f330 100644
--- a/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Linksets/AdvisoryObservationFactoryTests.cs
+++ b/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Linksets/AdvisoryObservationFactoryTests.cs
@@ -13,11 +13,11 @@ public sealed class AdvisoryObservationFactoryTests
private static readonly DateTimeOffset SampleTimestamp = DateTimeOffset.Parse("2025-10-26T12:34:56Z");
[Fact]
- public void Create_NormalizesLinksetIdentifiersAndReferences()
- {
- var factory = new AdvisoryObservationFactory();
- var rawDocument = BuildRawDocument(
- identifiers: new RawIdentifiers(
+ public void Create_PreservesLinksetOrderAndDuplicates()
+ {
+ var factory = new AdvisoryObservationFactory();
+ var rawDocument = BuildRawDocument(
+ identifiers: new RawIdentifiers(
Aliases: ImmutableArray.Create(" CVE-2025-0001 ", "ghsa-XXXX-YYYY"),
PrimaryId: "GHSA-XXXX-YYYY"),
linkset: new RawLinkset
@@ -29,16 +29,27 @@ public sealed class AdvisoryObservationFactoryTests
new RawReference("Advisory", " https://example.test/advisory "),
new RawReference("ADVISORY", "https://example.test/advisory"))
});
-
- var observation = factory.Create(rawDocument, SampleTimestamp);
-
- Assert.Equal(SampleTimestamp, observation.CreatedAt);
- Assert.Equal(new[] { "cve-2025-0001", "ghsa-xxxx-yyyy" }, observation.Linkset.Aliases);
- Assert.Equal(new[] { "pkg:npm/left-pad@1.0.0" }, observation.Linkset.Purls);
- Assert.Equal(new[] { "cpe:2.3:a:example:product:1.0:*:*:*:*:*:*:*" }, observation.Linkset.Cpes);
- var reference = Assert.Single(observation.Linkset.References);
- Assert.Equal("advisory", reference.Type);
- Assert.Equal("https://example.test/advisory", reference.Url);
+
+ var observation = factory.Create(rawDocument, SampleTimestamp);
+
+ Assert.Equal(SampleTimestamp, observation.CreatedAt);
+ Assert.Equal(
+ new[] { "GHSA-XXXX-YYYY", "CVE-2025-0001", "ghsa-XXXX-YYYY", "CVE-2025-0001" },
+ observation.Linkset.Aliases);
+ Assert.Equal(
+ new[] { "pkg:NPM/left-pad@1.0.0", "pkg:npm/left-pad@1.0.0?foo=bar" },
+ observation.Linkset.Purls);
+ Assert.Equal(
+ new[] { "cpe:/a:Example:Product:1.0", "cpe:/a:example:product:1.0" },
+ observation.Linkset.Cpes);
+ Assert.Equal(2, observation.Linkset.References.Length);
+ Assert.All(
+ observation.Linkset.References,
+ reference =>
+ {
+ Assert.Equal("advisory", reference.Type);
+ Assert.Equal("https://example.test/advisory", reference.Url);
+ });
Assert.Equal(
new[] { "GHSA-XXXX-YYYY", " CVE-2025-0001 ", "ghsa-XXXX-YYYY", " CVE-2025-0001 " },
diff --git a/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Observations/AdvisoryObservationQueryServiceTests.cs b/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Observations/AdvisoryObservationQueryServiceTests.cs
index 4d25ea71e..be7fbb1c6 100644
--- a/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Observations/AdvisoryObservationQueryServiceTests.cs
+++ b/src/Concelier/__Tests/StellaOps.Concelier.Core.Tests/Observations/AdvisoryObservationQueryServiceTests.cs
@@ -1,3 +1,4 @@
+using System;
using System.Collections.Immutable;
using System.Linq;
using System.Text.Json.Nodes;
@@ -52,9 +53,9 @@ public sealed class AdvisoryObservationQueryServiceTests
Assert.Equal("tenant-a:osv:beta:1", result.Observations[0].ObservationId);
Assert.Equal("tenant-a:ghsa:alpha:1", result.Observations[1].ObservationId);
- Assert.Equal(
- new[] { "cve-2025-0001", "cve-2025-0002", "ghsa-xyzz" },
- result.Linkset.Aliases);
+ Assert.Equal(
+ new[] { "CVE-2025-0001", "CVE-2025-0002", "GHSA-xyzz" },
+ result.Linkset.Aliases);
Assert.Equal(
new[] { "pkg:npm/package-a@1.0.0", "pkg:pypi/package-b@2.0.0" },
@@ -103,8 +104,11 @@ public sealed class AdvisoryObservationQueryServiceTests
CancellationToken.None);
Assert.Equal(2, result.Observations.Length);
- Assert.All(result.Observations, observation =>
- Assert.Contains(observation.Linkset.Aliases, alias => alias is "cve-2025-0001" or "cve-2025-9999"));
+ Assert.All(result.Observations, observation =>
+ Assert.Contains(
+ observation.Linkset.Aliases,
+ alias => alias.Equals("CVE-2025-0001", StringComparison.OrdinalIgnoreCase)
+ || alias.Equals("CVE-2025-9999", StringComparison.OrdinalIgnoreCase)));
Assert.False(result.HasMore);
Assert.Null(result.NextCursor);
diff --git a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj
index 76d0dee95..1432586b1 100644
--- a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj
+++ b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/StellaOps.Concelier.WebService.Tests.csproj
@@ -10,5 +10,8 @@
+
-
\ No newline at end of file
+
diff --git a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/WebServiceEndpointsTests.cs b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/WebServiceEndpointsTests.cs
index a138eaa1b..f4893ab03 100644
--- a/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/WebServiceEndpointsTests.cs
+++ b/src/Concelier/__Tests/StellaOps.Concelier.WebService.Tests/WebServiceEndpointsTests.cs
@@ -221,7 +221,7 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
Assert.NotNull(ingestResponse.Headers.Location);
var locationValue = ingestResponse.Headers.Location!.ToString();
Assert.False(string.IsNullOrWhiteSpace(locationValue));
- var lastSlashIndex = locationValue.LastIndexOf('/', StringComparison.Ordinal);
+ var lastSlashIndex = locationValue.LastIndexOf('/');
var idSegment = lastSlashIndex >= 0
? locationValue[(lastSlashIndex + 1)..]
: locationValue;
@@ -886,15 +886,61 @@ public sealed class WebServiceEndpointsTests : IAsyncLifetime
var limitedResponse = await client.GetAsync("/concelier/exports/index.json");
Assert.Equal((HttpStatusCode)429, limitedResponse.StatusCode);
Assert.NotNull(limitedResponse.Headers.RetryAfter);
- Assert.True(limitedResponse.Headers.RetryAfter!.Delta.HasValue);
- Assert.True(limitedResponse.Headers.RetryAfter!.Delta!.Value.TotalSeconds > 0);
- }
-
-
- [Fact]
- public async Task JobsEndpointsAllowBypassWhenAuthorityEnabled()
- {
- var environment = new Dictionary
+ Assert.True(limitedResponse.Headers.RetryAfter!.Delta.HasValue);
+ Assert.True(limitedResponse.Headers.RetryAfter!.Delta!.Value.TotalSeconds > 0);
+ }
+
+ [Fact]
+ public void MergeModuleDisabledWhenFeatureFlagEnabled()
+ {
+ var environment = new Dictionary
+ {
+ ["CONCELIER_FEATURES__NOMERGEENABLED"] = "true"
+ };
+
+ using var factory = new ConcelierApplicationFactory(
+ _runner.ConnectionString,
+ authorityConfigure: null,
+ environmentOverrides: environment);
+ using var scope = factory.Services.CreateScope();
+ var provider = scope.ServiceProvider;
+
+#pragma warning disable CS0618, CONCELIER0001, CONCELIER0002 // Checking deprecated service registration state.
+ Assert.Null(provider.GetService());
+#pragma warning restore CS0618, CONCELIER0001, CONCELIER0002
+
+ var schedulerOptions = provider.GetRequiredService>().Value;
+ Assert.DoesNotContain("merge:reconcile", schedulerOptions.Definitions.Keys);
+ }
+
+ [Fact]
+ public void MergeJobRemainsWhenAllowlisted()
+ {
+ var environment = new Dictionary
+ {
+ ["CONCELIER_FEATURES__MERGEJOBALLOWLIST__0"] = "merge:reconcile"
+ };
+
+ using var factory = new ConcelierApplicationFactory(
+ _runner.ConnectionString,
+ authorityConfigure: null,
+ environmentOverrides: environment);
+ using var scope = factory.Services.CreateScope();
+ var provider = scope.ServiceProvider;
+
+#pragma warning disable CS0618, CONCELIER0001, CONCELIER0002 // Checking deprecated service registration state.
+ Assert.NotNull(provider.GetService());
+#pragma warning restore CS0618, CONCELIER0001, CONCELIER0002
+
+ var schedulerOptions = provider.GetRequiredService>().Value;
+ Assert.Contains("merge:reconcile", schedulerOptions.Definitions.Keys);
+ }
+
+
+ [Fact]
+ public async Task JobsEndpointsAllowBypassWhenAuthorityEnabled()
+ {
+ var environment = new Dictionary
{
["CONCELIER_AUTHORITY__ENABLED"] = "true",
["CONCELIER_AUTHORITY__ALLOWANONYMOUSFALLBACK"] = "false",
diff --git a/src/Excititor/StellaOps.Excititor.WebService/Program.cs b/src/Excititor/StellaOps.Excititor.WebService/Program.cs
index 9bdb2a7f2..2860bca32 100644
--- a/src/Excititor/StellaOps.Excititor.WebService/Program.cs
+++ b/src/Excititor/StellaOps.Excititor.WebService/Program.cs
@@ -18,7 +18,6 @@ using StellaOps.Excititor.Policy;
using StellaOps.Excititor.Storage.Mongo;
using StellaOps.Excititor.WebService.Endpoints;
using StellaOps.Excititor.WebService.Services;
-using StellaOps.Excititor.Core;
using StellaOps.Excititor.Core.Aoc;
var builder = WebApplication.CreateBuilder(args);
diff --git a/src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs b/src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs
index 933601022..940c1e203 100644
--- a/src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs
+++ b/src/Excititor/StellaOps.Excititor.Worker/Signature/WorkerSignatureVerifier.cs
@@ -84,10 +84,13 @@ internal sealed class WorkerSignatureVerifier : IVexSignatureVerifier
throw new ExcititorAocGuardException(AocGuardResult.FromViolations(new[] { violation }));
}
- VexSignatureMetadata? signatureMetadata = null;
- if (document.Format == VexDocumentFormat.OciAttestation && _attestationVerifier is not null)
+ VexSignatureMetadata? signatureMetadata = null;
+ VexAttestationDiagnostics? attestationDiagnostics = null;
+ if (document.Format == VexDocumentFormat.OciAttestation && _attestationVerifier is not null)
{
- signatureMetadata = await VerifyAttestationAsync(document, metadata, cancellationToken).ConfigureAwait(false);
+ var attestationResult = await VerifyAttestationAsync(document, metadata, cancellationToken).ConfigureAwait(false);
+ signatureMetadata = attestationResult.Metadata;
+ attestationDiagnostics = attestationResult.Diagnostics;
}
signatureMetadata ??= ExtractSignatureMetadata(metadata);
@@ -96,31 +99,40 @@ internal sealed class WorkerSignatureVerifier : IVexSignatureVerifier
signatureMetadata = await AttachIssuerTrustAsync(signatureMetadata, metadata, cancellationToken).ConfigureAwait(false);
}
var resultLabel = signatureMetadata is null ? "skipped" : "ok";
- RecordVerification(document.ProviderId, metadata, resultLabel);
-
- if (resultLabel == "skipped")
- {
+ if (attestationDiagnostics is not null)
+ {
+ resultLabel = attestationDiagnostics.Result ?? resultLabel;
+ }
+
+ if (attestationDiagnostics is null)
+ {
+ RecordVerification(document.ProviderId, metadata, resultLabel);
+ }
+
+ if (resultLabel == "skipped")
+ {
_logger.LogDebug(
"Signature verification skipped for provider {ProviderId} (no signature metadata).",
document.ProviderId);
}
else
{
- _logger.LogInformation(
- "Signature metadata recorded for provider {ProviderId} (type={SignatureType}, subject={Subject}, issuer={Issuer}).",
- document.ProviderId,
- signatureMetadata!.Type,
- signatureMetadata.Subject ?? "",
- signatureMetadata.Issuer ?? "");
- }
-
- return signatureMetadata;
- }
-
- private async ValueTask VerifyAttestationAsync(
- VexRawDocument document,
- ImmutableDictionary metadata,
- CancellationToken cancellationToken)
+ _logger.LogInformation(
+ "Signature metadata recorded for provider {ProviderId} (type={SignatureType}, subject={Subject}, issuer={Issuer}, result={Result}).",
+ document.ProviderId,
+ signatureMetadata!.Type,
+ signatureMetadata.Subject ?? "",
+ signatureMetadata.Issuer ?? "",
+ resultLabel);
+ }
+
+ return signatureMetadata;
+ }
+
+ private async ValueTask<(VexSignatureMetadata Metadata, VexAttestationDiagnostics Diagnostics)> VerifyAttestationAsync(
+ VexRawDocument document,
+ ImmutableDictionary metadata,
+ CancellationToken cancellationToken)
{
try
{
@@ -146,37 +158,48 @@ internal sealed class WorkerSignatureVerifier : IVexSignatureVerifier
attestationMetadata,
envelopeJson);
- var verification = await _attestationVerifier!
- .VerifyAsync(verificationRequest, cancellationToken)
- .ConfigureAwait(false);
- if (!verification.IsValid)
- {
- var diagnostics = string.Join(", ", verification.Diagnostics.Select(kvp => $"{kvp.Key}={kvp.Value}"));
- _logger.LogError(
- "Attestation verification failed for provider {ProviderId} (uri={SourceUri}) diagnostics={Diagnostics}",
- document.ProviderId,
- document.SourceUri,
- diagnostics);
-
- var violation = AocViolation.Create(
- AocViolationCode.SignatureInvalid,
- "/upstream/signature",
- "Attestation verification failed.");
-
- RecordVerification(document.ProviderId, metadata, "fail");
- throw new ExcititorAocGuardException(AocGuardResult.FromViolations(new[] { violation }));
- }
-
- _logger.LogInformation(
- "Attestation verification succeeded for provider {ProviderId} (predicate={PredicateType}, subject={Subject}).",
- document.ProviderId,
- attestationMetadata.PredicateType,
- statement.Subject[0].Name ?? "");
-
- return BuildSignatureMetadata(statement, metadata, attestationMetadata, verification.Diagnostics);
- }
- catch (ExcititorAocGuardException)
- {
+ var verification = await _attestationVerifier!
+ .VerifyAsync(verificationRequest, cancellationToken)
+ .ConfigureAwait(false);
+ var diagnosticsSnapshot = verification.Diagnostics;
+
+ if (!verification.IsValid)
+ {
+ var failureReason = diagnosticsSnapshot.FailureReason ?? "verification_failed";
+ var resultTag = diagnosticsSnapshot.Result ?? "invalid";
+
+ RecordVerification(document.ProviderId, metadata, resultTag);
+ _logger.LogError(
+ "Attestation verification failed for provider {ProviderId} (uri={SourceUri}) result={Result} failure={FailureReason} diagnostics={@Diagnostics}",
+ document.ProviderId,
+ document.SourceUri,
+ resultTag,
+ failureReason,
+ diagnosticsSnapshot);
+
+ var violation = AocViolation.Create(
+ AocViolationCode.SignatureInvalid,
+ "/upstream/signature",
+ "Attestation verification failed.");
+
+ throw new ExcititorAocGuardException(AocGuardResult.FromViolations(new[] { violation }));
+ }
+
+ var successResult = diagnosticsSnapshot.Result ?? "valid";
+ RecordVerification(document.ProviderId, metadata, successResult);
+
+ _logger.LogInformation(
+ "Attestation verification succeeded for provider {ProviderId} (predicate={PredicateType}, subject={Subject}, result={Result}).",
+ document.ProviderId,
+ attestationMetadata.PredicateType,
+ statement.Subject[0].Name ?? "",
+ successResult);
+
+ var signatureMetadata = BuildSignatureMetadata(statement, metadata, attestationMetadata, diagnosticsSnapshot);
+ return (signatureMetadata, diagnosticsSnapshot);
+ }
+ catch (ExcititorAocGuardException)
+ {
throw;
}
catch (Exception ex)
@@ -192,10 +215,10 @@ internal sealed class WorkerSignatureVerifier : IVexSignatureVerifier
"/upstream/signature",
$"Attestation verification encountered an error: {ex.Message}");
- RecordVerification(document.ProviderId, metadata, "fail");
- throw new ExcititorAocGuardException(AocGuardResult.FromViolations(new[] { violation }));
- }
- }
+ RecordVerification(document.ProviderId, metadata, "error");
+ throw new ExcititorAocGuardException(AocGuardResult.FromViolations(new[] { violation }));
+ }
+ }
private VexAttestationRequest BuildAttestationRequest(VexInTotoStatement statement, VexAttestationPredicate predicate)
{
@@ -252,11 +275,11 @@ internal sealed class WorkerSignatureVerifier : IVexSignatureVerifier
signedAt);
}
- private VexSignatureMetadata BuildSignatureMetadata(
- VexInTotoStatement statement,
- ImmutableDictionary metadata,
- VexAttestationMetadata attestationMetadata,
- ImmutableDictionary diagnostics)
+ private VexSignatureMetadata BuildSignatureMetadata(
+ VexInTotoStatement statement,
+ ImmutableDictionary metadata,
+ VexAttestationMetadata attestationMetadata,
+ VexAttestationDiagnostics diagnostics)
{
metadata.TryGetValue("vex.signature.type", out var type);
metadata.TryGetValue("vex.provenance.cosign.subject", out var subject);
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/EXCITITOR-ATTEST-01-003-plan.md b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/EXCITITOR-ATTEST-01-003-plan.md
index dfd64acf9..3c774ce8b 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/EXCITITOR-ATTEST-01-003-plan.md
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/EXCITITOR-ATTEST-01-003-plan.md
@@ -13,16 +13,18 @@
3. Emit observability signals (logs, metrics, optional tracing) that can run offline and degrade gracefully when transparency services are unreachable.
4. Add regression tests (unit + integration) covering positive path, negative path, and offline fallback scenarios.
-## 2. Deliverables
-
-- `IVexAttestationVerifier` abstraction + `VexAttestationVerifier` implementation inside `StellaOps.Excititor.Attestation`, encapsulating DSSE validation, predicate checks, artifact digest confirmation, Rekor inclusion verification, and deterministic diagnostics.
-- DI wiring (extension method) for registering verifier + instrumentation dependencies alongside the existing signer/rekor client.
-- Shared `VexAttestationDiagnostics` record describing normalized diagnostic keys consumed by Worker/WebService logging.
-- Metrics utility (`AttestationMetrics`) exposing counters/histograms via `System.Diagnostics.Metrics`, exported under `StellaOps.Excititor.Attestation` meter.
-- Activity source (`AttestationActivitySource`) for optional tracing spans around sign/verify operations.
-- Documentation updates (`EXCITITOR-ATTEST-01-003-plan.md`, `TASKS.md` notes) describing instrumentation + test expectations.
-- Test coverage in `StellaOps.Excititor.Attestation.Tests` (unit) and scaffolding notes for WebService/Worker integration tests.
-
+## 2. Deliverables
+
+- `IVexAttestationVerifier` abstraction + `VexAttestationVerifier` implementation inside `StellaOps.Excititor.Attestation`, encapsulating DSSE validation, predicate checks, artifact digest confirmation, Rekor inclusion verification, and deterministic diagnostics.
+- DI wiring (extension method) for registering verifier + instrumentation dependencies alongside the existing signer/rekor client.
+- Shared `VexAttestationDiagnostics` record describing normalized diagnostic keys consumed by Worker/WebService logging.
+- Metrics utility (`AttestationMetrics`) exposing counters/histograms via `System.Diagnostics.Metrics`, exported under `StellaOps.Excititor.Attestation` meter.
+- Activity source (`AttestationActivitySource`) for optional tracing spans around sign/verify operations.
+- 2025-11-05: Implemented `VexAttestationDiagnostics`, activity tagging via `VexAttestationActivitySource`, and updated verifier/tests to emit structured failure reasons.
+- 2025-11-05 (pm): Worker attestation verifier now records structured diagnostics/metrics and logs result/failure reasons using `VexAttestationDiagnostics`; attestation success/failure labels propagate to verification counters.
+- Documentation updates (`EXCITITOR-ATTEST-01-003-plan.md`, `TASKS.md` notes) describing instrumentation + test expectations.
+- Test coverage in `StellaOps.Excititor.Attestation.Tests` (unit) and scaffolding notes for WebService/Worker integration tests.
+
## 3. Verification Flow
### 3.1 Inputs
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/TASKS.md b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/TASKS.md
index 0260833f6..b7d212323 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/TASKS.md
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/TASKS.md
@@ -1,6 +1,9 @@
-If you are working on this file you need to read docs/modules/excititor/ARCHITECTURE.md and ./AGENTS.md).
-# TASKS
-| Task | Owner(s) | Depends on | Notes |
-|---|---|---|---|
-|EXCITITOR-ATTEST-01-003 – Verification suite & observability|Team Excititor Attestation|EXCITITOR-ATTEST-01-002|DOING (2025-10-22) – Continuing implementation: build `IVexAttestationVerifier`, wire metrics/logging, and add regression tests. Draft plan in `EXCITITOR-ATTEST-01-003-plan.md` (2025-10-19) guides scope; updating with worknotes as progress lands.
2025-10-31: Verifier now tolerates duplicate source providers from AOC raw projections, downgrades offline Rekor verification to a degraded result, and enforces trusted signer registry checks with detailed diagnostics/tests.|
-> Remark (2025-10-22): Added verifier implementation + metrics/tests; next steps include wiring into WebService/Worker flows and expanding negative-path coverage.
+If you are working on this file you need to read docs/modules/excititor/ARCHITECTURE.md and ./AGENTS.md).
+# TASKS
+| Task | Owner(s) | Depends on | Notes |
+|---|---|---|---|
+|EXCITITOR-ATTEST-01-003 – Verification suite & observability|Team Excititor Attestation|EXCITITOR-ATTEST-01-002|TODO (2025-11-06) – Continuing implementation: build `IVexAttestationVerifier`, wire metrics/logging, and add regression tests. Draft plan in `EXCITITOR-ATTEST-01-003-plan.md` (2025-10-19) guides scope; updating with worknotes as progress lands.
2025-10-31: Verifier now tolerates duplicate source providers from AOC raw projections, downgrades offline Rekor verification to a degraded result, and enforces trusted signer registry checks with detailed diagnostics/tests.
2025-11-05 14:35Z: Picking up diagnostics record/ActivitySource work and aligning metrics dimensions before wiring verifier into WebService/Worker paths.|
+> 2025-11-05 19:10Z: Worker signature verifier now emits structured diagnostics/metrics via `VexAttestationDiagnostics`; attestation verification results flow into metric labels and logs.
+> 2025-11-06 07:12Z: Export verifier builds unblocked; Excititor worker + web service test suites pass with diagnostics wiring (`dotnet test` invocations succeed with staged libssl1.1).
+> 2025-11-06 07:55Z: Paused after documenting OpenSSL shim usage; follow-up automation tracked under `DEVOPS-OPENSSL-11-001/002`.
+> Remark (2025-10-22): Added verifier implementation + metrics/tests; next steps include wiring into WebService/Worker flows and expanding negative-path coverage.
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationActivitySource.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationActivitySource.cs
new file mode 100644
index 000000000..d8699a323
--- /dev/null
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationActivitySource.cs
@@ -0,0 +1,10 @@
+using System.Diagnostics;
+
+namespace StellaOps.Excititor.Attestation.Verification;
+
+public static class VexAttestationActivitySource
+{
+ public const string Name = "StellaOps.Excititor.Attestation";
+
+ public static readonly ActivitySource Value = new(Name);
+}
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationVerifier.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationVerifier.cs
index c292f0fa4..b3a87b5cf 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationVerifier.cs
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Attestation/Verification/VexAttestationVerifier.cs
@@ -1,8 +1,8 @@
using System;
-using System.Collections.Generic;
-using System.Collections.Immutable;
-using System.Diagnostics;
-using System.Linq;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+using System.Diagnostics;
+using System.Linq;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
@@ -59,104 +59,120 @@ internal sealed class VexAttestationVerifier : IVexAttestationVerifier
public async ValueTask VerifyAsync(
VexAttestationVerificationRequest request,
CancellationToken cancellationToken)
- {
- ArgumentNullException.ThrowIfNull(request);
-
- var stopwatch = Stopwatch.StartNew();
- var diagnostics = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal);
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ var stopwatch = Stopwatch.StartNew();
+ var diagnostics = ImmutableDictionary.CreateBuilder(StringComparer.Ordinal);
var resultLabel = "valid";
var rekorState = "skipped";
var component = request.IsReverify ? "worker" : "webservice";
+ void SetFailure(string reason) => diagnostics["failure_reason"] = reason;
+ using var activity = VexAttestationActivitySource.Value.StartActivity("Verify", ActivityKind.Internal);
+ activity?.SetTag("attestation.component", component);
+ activity?.SetTag("attestation.export_id", request.Attestation.ExportId);
try
{
- if (string.IsNullOrWhiteSpace(request.Envelope))
- {
- diagnostics["envelope.state"] = "missing";
- _logger.LogWarning("Attestation envelope is missing for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!TryDeserializeEnvelope(request.Envelope, out var envelope, diagnostics))
- {
- _logger.LogWarning("Failed to deserialize attestation envelope for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!string.Equals(envelope.PayloadType, VexDsseBuilder.PayloadType, StringComparison.OrdinalIgnoreCase))
- {
- diagnostics["payload.type"] = envelope.PayloadType ?? string.Empty;
- _logger.LogWarning(
- "Unexpected DSSE payload type {PayloadType} for export {ExportId}",
- envelope.PayloadType,
- request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (envelope.Signatures is null || envelope.Signatures.Count == 0)
- {
- diagnostics["signature.state"] = "missing";
- _logger.LogWarning("Attestation envelope for export {ExportId} does not contain signatures.", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- var payloadBase64 = envelope.Payload ?? string.Empty;
- if (!TryDecodePayload(payloadBase64, out var payloadBytes, diagnostics))
- {
- _logger.LogWarning("Failed to decode attestation payload for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!TryDeserializeStatement(payloadBytes, out var statement, diagnostics))
- {
- _logger.LogWarning("Failed to deserialize DSSE statement for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!ValidatePredicateType(statement, request, diagnostics))
- {
- _logger.LogWarning("Predicate type mismatch for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!ValidateSubject(statement, request, diagnostics))
- {
- _logger.LogWarning("Subject mismatch for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!ValidatePredicate(statement, request, diagnostics))
- {
- _logger.LogWarning("Predicate payload mismatch for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!ValidateMetadataDigest(envelope, request.Metadata, diagnostics))
- {
- _logger.LogWarning("Attestation digest mismatch for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
- if (!ValidateSignedAt(request.Metadata, request.Attestation.CreatedAt, diagnostics))
- {
- _logger.LogWarning("SignedAt validation failed for export {ExportId}", request.Attestation.ExportId);
- resultLabel = "invalid";
- return BuildResult(false);
- }
-
+ if (string.IsNullOrWhiteSpace(request.Envelope))
+ {
+ diagnostics["envelope.state"] = "missing";
+ SetFailure("missing_envelope");
+ _logger.LogWarning("Attestation envelope is missing for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!TryDeserializeEnvelope(request.Envelope, out var envelope, diagnostics))
+ {
+ SetFailure("invalid_envelope");
+ _logger.LogWarning("Failed to deserialize attestation envelope for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!string.Equals(envelope.PayloadType, VexDsseBuilder.PayloadType, StringComparison.OrdinalIgnoreCase))
+ {
+ diagnostics["payload.type"] = envelope.PayloadType ?? string.Empty;
+ SetFailure("unexpected_payload_type");
+ _logger.LogWarning(
+ "Unexpected DSSE payload type {PayloadType} for export {ExportId}",
+ envelope.PayloadType,
+ request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (envelope.Signatures is null || envelope.Signatures.Count == 0)
+ {
+ diagnostics["signature.state"] = "missing";
+ SetFailure("missing_signature");
+ _logger.LogWarning("Attestation envelope for export {ExportId} does not contain signatures.", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ var payloadBase64 = envelope.Payload ?? string.Empty;
+ if (!TryDecodePayload(payloadBase64, out var payloadBytes, diagnostics))
+ {
+ SetFailure("payload_decode_failed");
+ _logger.LogWarning("Failed to decode attestation payload for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!TryDeserializeStatement(payloadBytes, out var statement, diagnostics))
+ {
+ SetFailure("invalid_statement");
+ _logger.LogWarning("Failed to deserialize DSSE statement for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!ValidatePredicateType(statement, request, diagnostics))
+ {
+ SetFailure("predicate_type_mismatch");
+ _logger.LogWarning("Predicate type mismatch for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!ValidateSubject(statement, request, diagnostics))
+ {
+ SetFailure("subject_mismatch");
+ _logger.LogWarning("Subject mismatch for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!ValidatePredicate(statement, request, diagnostics))
+ {
+ SetFailure("predicate_mismatch");
+ _logger.LogWarning("Predicate payload mismatch for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!ValidateMetadataDigest(envelope, request.Metadata, diagnostics))
+ {
+ SetFailure("envelope_digest_mismatch");
+ _logger.LogWarning("Attestation digest mismatch for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
+ if (!ValidateSignedAt(request.Metadata, request.Attestation.CreatedAt, diagnostics))
+ {
+ SetFailure("signedat_out_of_range");
+ _logger.LogWarning("SignedAt validation failed for export {ExportId}", request.Attestation.ExportId);
+ resultLabel = "invalid";
+ return BuildResult(false);
+ }
+
rekorState = await VerifyTransparencyAsync(request.Metadata, diagnostics, cancellationToken).ConfigureAwait(false);
if (rekorState is "missing" or "unverified" or "client_unavailable")
{
+ SetFailure(rekorState);
resultLabel = "invalid";
return BuildResult(false);
}
@@ -164,6 +180,9 @@ internal sealed class VexAttestationVerifier : IVexAttestationVerifier
var signaturesVerified = await VerifySignaturesAsync(payloadBytes, envelope.Signatures, diagnostics, cancellationToken).ConfigureAwait(false);
if (!signaturesVerified)
{
+ diagnostics["failure_reason"] = diagnostics.TryGetValue("signature.reason", out var reason)
+ ? reason
+ : "signature_verification_failed";
if (_options.RequireSignatureVerification)
{
resultLabel = "invalid";
@@ -183,13 +202,16 @@ internal sealed class VexAttestationVerifier : IVexAttestationVerifier
catch (Exception ex)
{
diagnostics["error"] = ex.GetType().Name;
- diagnostics["error.message"] = ex.Message; resultLabel = "error";
- _logger.LogError(ex, "Unexpected exception verifying attestation for export {ExportId}", request.Attestation.ExportId);
- return BuildResult(false);
- }
- finally
- {
- stopwatch.Stop();
+ diagnostics["error.message"] = ex.Message; resultLabel = "error";
+ _logger.LogError(ex, "Unexpected exception verifying attestation for export {ExportId}", request.Attestation.ExportId);
+ diagnostics["failure_reason"] = diagnostics.TryGetValue("error", out var errorCode)
+ ? errorCode
+ : ex.GetType().Name;
+ return BuildResult(false);
+ }
+ finally
+ {
+ stopwatch.Stop();
var tags = new KeyValuePair[]
{
new("result", resultLabel),
@@ -200,12 +222,32 @@ internal sealed class VexAttestationVerifier : IVexAttestationVerifier
_metrics.VerifyDuration.Record(stopwatch.Elapsed.TotalSeconds, tags);
}
- VexAttestationVerification BuildResult(bool isValid)
- {
- diagnostics["result"] = resultLabel;
- diagnostics["component"] = component;
+ VexAttestationVerification BuildResult(bool isValid)
+ {
+ diagnostics["result"] = resultLabel;
+ diagnostics["component"] = component;
diagnostics["rekor.state"] = rekorState;
- return new VexAttestationVerification(isValid, diagnostics.ToImmutable());
+ var snapshot = VexAttestationDiagnostics.FromBuilder(diagnostics);
+
+ if (activity is { } currentActivity)
+ {
+ currentActivity.SetTag("attestation.result", resultLabel);
+ currentActivity.SetTag("attestation.rekor", rekorState);
+ if (!isValid)
+ {
+ var failure = snapshot.FailureReason ?? "verification_failed";
+ currentActivity.SetStatus(ActivityStatusCode.Error, failure);
+ currentActivity.SetTag("attestation.failure_reason", failure);
+ }
+ else
+ {
+ currentActivity.SetStatus(resultLabel is "degraded"
+ ? ActivityStatusCode.Ok
+ : ActivityStatusCode.Ok);
+ }
+ }
+
+ return new VexAttestationVerification(isValid, snapshot);
}
}
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj b/src/Excititor/__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj
index 2fadfde99..d6bc7e3ad 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Core/StellaOps.Excititor.Core.csproj
@@ -14,4 +14,4 @@
-
\ No newline at end of file
+
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationAbstractions.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationAbstractions.cs
index 6e3b3bc43..fd2f3ec2a 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationAbstractions.cs
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationAbstractions.cs
@@ -1,7 +1,8 @@
using System;
using System.Collections.Immutable;
using System.Threading;
-using System.Threading.Tasks;
+using System.Threading.Tasks;
+using StellaOps.Excititor.Attestation.Verification;
namespace StellaOps.Excititor.Core;
@@ -33,4 +34,4 @@ public sealed record VexAttestationVerificationRequest(
public sealed record VexAttestationVerification(
bool IsValid,
- ImmutableDictionary Diagnostics);
+ VexAttestationDiagnostics Diagnostics);
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationDiagnostics.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationDiagnostics.cs
new file mode 100644
index 000000000..329ae6507
--- /dev/null
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Core/VexAttestationDiagnostics.cs
@@ -0,0 +1,57 @@
+using System.Collections;
+using System.Collections.Generic;
+using System.Collections.Immutable;
+
+namespace StellaOps.Excititor.Attestation.Verification;
+
+public sealed class VexAttestationDiagnostics : IReadOnlyDictionary
+{
+ private readonly ImmutableDictionary _values;
+
+ private VexAttestationDiagnostics(ImmutableDictionary values)
+ {
+ _values = values ?? ImmutableDictionary.Empty;
+ }
+
+ public static VexAttestationDiagnostics FromBuilder(ImmutableDictionary.Builder builder)
+ {
+ ArgumentNullException.ThrowIfNull(builder);
+ return new(builder.ToImmutable());
+ }
+
+ public static VexAttestationDiagnostics Empty { get; } = new(ImmutableDictionary.Empty);
+
+ public string? Result => TryGetValue("result", out var value) ? value : null;
+
+ public string? Component => TryGetValue("component", out var value) ? value : null;
+
+ public string? RekorState => TryGetValue("rekor.state", out var value) ? value : null;
+
+ public string? FailureReason => TryGetValue("failure_reason", out var value) ? value : null;
+
+ public string this[string key] => _values[key];
+
+ public IEnumerable Keys => _values.Keys;
+
+ public IEnumerable Values => _values.Values;
+
+ public int Count => _values.Count;
+
+ public bool ContainsKey(string key) => _values.ContainsKey(key);
+
+ public bool TryGetValue(string key, out string value)
+ {
+ if (_values.TryGetValue(key, out var stored))
+ {
+ value = stored;
+ return true;
+ }
+
+ value = string.Empty;
+ return false;
+ }
+
+ public IEnumerator> GetEnumerator() => _values.GetEnumerator();
+
+ IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
+}
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Export/ExportEngine.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Export/ExportEngine.cs
index 5f37d8b4c..453d09baf 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Export/ExportEngine.cs
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Export/ExportEngine.cs
@@ -98,6 +98,7 @@ public sealed class VexExportEngine : IExportEngine
cached.PolicyDigest,
cached.ConsensusDigest,
cached.ScoreDigest,
+ cached.QuietProvenance,
cached.Attestation,
cached.SizeBytes);
}
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexExportEnvelopeBuilder.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexExportEnvelopeBuilder.cs
index 5ff91ab94..653fa737c 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexExportEnvelopeBuilder.cs
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexExportEnvelopeBuilder.cs
@@ -130,7 +130,7 @@ internal static class VexExportEnvelopeBuilder
}
}
-internal sealed record VexExportEnvelopeContext(
+public sealed record VexExportEnvelopeContext(
ImmutableArray Consensus,
string ConsensusCanonicalJson,
VexContentAddress ConsensusDigest,
diff --git a/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexMirrorBundlePublisher.cs b/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexMirrorBundlePublisher.cs
index 24276e9f5..acf4eca92 100644
--- a/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexMirrorBundlePublisher.cs
+++ b/src/Excititor/__Libraries/StellaOps.Excititor.Export/VexMirrorBundlePublisher.cs
@@ -280,7 +280,7 @@ public sealed class VexMirrorBundlePublisher : IVexMirrorBundlePublisher
ToRelativePath(mirrorRoot, manifestPath),
manifestBytes.LongLength,
ComputeDigest(manifestBytes),
- signature: null);
+ Signature: null);
var bundleDescriptor = manifestDocument.Bundle with
{
@@ -298,7 +298,7 @@ public sealed class VexMirrorBundlePublisher : IVexMirrorBundlePublisher
manifestDocument.DomainId,
manifestDocument.DisplayName,
manifestDocument.GeneratedAt,
- manifestDocument.Exports.Length,
+ manifestDocument.Exports.Count,
manifestDescriptor,
bundleDescriptor,
exportKeys));
@@ -474,6 +474,11 @@ public sealed class VexMirrorBundlePublisher : IVexMirrorBundlePublisher
private JsonMirrorSigningContext PrepareSigningContext(MirrorSigningOptions signingOptions)
{
+ if (_cryptoRegistry is null)
+ {
+ throw new InvalidOperationException("Mirror signing requires a crypto provider registry to be configured.");
+ }
+
var algorithm = string.IsNullOrWhiteSpace(signingOptions.Algorithm)
? SignatureAlgorithms.Es256
: signingOptions.Algorithm.Trim();
@@ -496,7 +501,7 @@ public sealed class VexMirrorBundlePublisher : IVexMirrorBundlePublisher
var provider = ResolveProvider(algorithm, providerHint);
var signingKey = LoadSigningKey(signingOptions, provider, algorithm);
provider.UpsertSigningKey(signingKey);
- resolved = _cryptoRegistry.ResolveSigner(CryptoCapability.Signing, algorithm, new CryptoKeyReference(keyId, provider.Name), provider.Name);
+ resolved = _cryptoRegistry!.ResolveSigner(CryptoCapability.Signing, algorithm, new CryptoKeyReference(keyId, provider.Name), provider.Name);
}
return new JsonMirrorSigningContext(resolved.Signer, algorithm, resolved.ProviderName, _timeProvider);
diff --git a/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationClientTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationClientTests.cs
index f8736cd55..c654b33be 100644
--- a/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationClientTests.cs
+++ b/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationClientTests.cs
@@ -85,6 +85,6 @@ public sealed class VexAttestationClientTests
private sealed class FakeVerifier : IVexAttestationVerifier
{
public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
- => ValueTask.FromResult(new VexAttestationVerification(true, ImmutableDictionary.Empty));
+ => ValueTask.FromResult(new VexAttestationVerification(true, VexAttestationDiagnostics.Empty));
}
}
diff --git a/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationVerifierTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationVerifierTests.cs
index 4a28dc9fa..b6f6f3408 100644
--- a/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationVerifierTests.cs
+++ b/src/Excititor/__Tests/StellaOps.Excititor.Attestation.Tests/VexAttestationVerifierTests.cs
@@ -16,42 +16,44 @@ public sealed class VexAttestationVerifierTests : IDisposable
{
private readonly VexAttestationMetrics _metrics = new();
- [Fact]
- public async Task VerifyAsync_ReturnsValid_WhenEnvelopeMatches()
- {
- var (request, metadata, envelope) = await CreateSignedAttestationAsync();
- var verifier = CreateVerifier(options => options.RequireTransparencyLog = false);
+ [Fact]
+ public async Task VerifyAsync_ReturnsValid_WhenEnvelopeMatches()
+ {
+ var (request, metadata, envelope) = await CreateSignedAttestationAsync();
+ var verifier = CreateVerifier(options => options.RequireTransparencyLog = false);
+
+ var verification = await verifier.VerifyAsync(
+ new VexAttestationVerificationRequest(request, metadata, envelope),
+ CancellationToken.None);
+
+ Assert.True(verification.IsValid);
+ Assert.Equal("valid", verification.Diagnostics.Result);
+ Assert.Null(verification.Diagnostics.FailureReason);
+ }
- var verification = await verifier.VerifyAsync(
- new VexAttestationVerificationRequest(request, metadata, envelope),
- CancellationToken.None);
+ [Fact]
+ public async Task VerifyAsync_ReturnsInvalid_WhenDigestMismatch()
+ {
+ var (request, metadata, envelope) = await CreateSignedAttestationAsync();
+ var verifier = CreateVerifier(options => options.RequireTransparencyLog = false);
+
+ var tamperedMetadata = new VexAttestationMetadata(
+ metadata.PredicateType,
+ metadata.Rekor,
+ "sha256:deadbeef",
+ metadata.SignedAt);
+
+ var verification = await verifier.VerifyAsync(
+ new VexAttestationVerificationRequest(request, tamperedMetadata, envelope),
+ CancellationToken.None);
+
+ Assert.False(verification.IsValid);
+ Assert.Equal("invalid", verification.Diagnostics.Result);
+ Assert.Equal("sha256:deadbeef", verification.Diagnostics["metadata.envelopeDigest"]);
+ Assert.Equal("envelope_digest_mismatch", verification.Diagnostics.FailureReason);
+ }
- Assert.True(verification.IsValid);
- Assert.Equal("valid", verification.Diagnostics["result"]);
- }
-
- [Fact]
- public async Task VerifyAsync_ReturnsInvalid_WhenDigestMismatch()
- {
- var (request, metadata, envelope) = await CreateSignedAttestationAsync();
- var verifier = CreateVerifier(options => options.RequireTransparencyLog = false);
-
- var tamperedMetadata = new VexAttestationMetadata(
- metadata.PredicateType,
- metadata.Rekor,
- "sha256:deadbeef",
- metadata.SignedAt);
-
- var verification = await verifier.VerifyAsync(
- new VexAttestationVerificationRequest(request, tamperedMetadata, envelope),
- CancellationToken.None);
-
- Assert.False(verification.IsValid);
- Assert.Equal("invalid", verification.Diagnostics["result"]);
- Assert.Equal("sha256:deadbeef", verification.Diagnostics["metadata.envelopeDigest"]);
- }
-
- [Fact]
+ [Fact]
public async Task VerifyAsync_AllowsOfflineTransparency_WhenConfigured()
{
var (request, metadata, envelope) = await CreateSignedAttestationAsync(includeRekor: true);
@@ -67,47 +69,50 @@ public sealed class VexAttestationVerifierTests : IDisposable
CancellationToken.None);
Assert.True(verification.IsValid);
- Assert.Equal("offline", verification.Diagnostics["rekor.state"]);
- Assert.Equal("degraded", verification.Diagnostics["result"]);
+ Assert.Equal("offline", verification.Diagnostics.RekorState);
+ Assert.Equal("degraded", verification.Diagnostics.Result);
+ Assert.Null(verification.Diagnostics.FailureReason);
}
[Fact]
public async Task VerifyAsync_ReturnsInvalid_WhenTransparencyRequiredAndMissing()
- {
- var (request, metadata, envelope) = await CreateSignedAttestationAsync(includeRekor: false);
- var verifier = CreateVerifier(options =>
- {
- options.RequireTransparencyLog = true;
- options.AllowOfflineTransparency = false;
- });
-
- var verification = await verifier.VerifyAsync(
- new VexAttestationVerificationRequest(request, metadata, envelope),
- CancellationToken.None);
-
- Assert.False(verification.IsValid);
- Assert.Equal("missing", verification.Diagnostics["rekor.state"]);
- Assert.Equal("invalid", verification.Diagnostics["result"]);
- }
-
- [Fact]
- public async Task VerifyAsync_ReturnsInvalid_WhenTransparencyUnavailableAndOfflineDisallowed()
- {
- var (request, metadata, envelope) = await CreateSignedAttestationAsync(includeRekor: true);
- var transparency = new ThrowingTransparencyLogClient();
- var verifier = CreateVerifier(options =>
- {
- options.RequireTransparencyLog = true;
- options.AllowOfflineTransparency = false;
- }, transparency);
-
- var verification = await verifier.VerifyAsync(
- new VexAttestationVerificationRequest(request, metadata, envelope),
- CancellationToken.None);
-
- Assert.False(verification.IsValid);
- Assert.Equal("unreachable", verification.Diagnostics["rekor.state"]);
- Assert.Equal("invalid", verification.Diagnostics["result"]);
+ {
+ var (request, metadata, envelope) = await CreateSignedAttestationAsync(includeRekor: false);
+ var verifier = CreateVerifier(options =>
+ {
+ options.RequireTransparencyLog = true;
+ options.AllowOfflineTransparency = false;
+ });
+
+ var verification = await verifier.VerifyAsync(
+ new VexAttestationVerificationRequest(request, metadata, envelope),
+ CancellationToken.None);
+
+ Assert.False(verification.IsValid);
+ Assert.Equal("missing", verification.Diagnostics.RekorState);
+ Assert.Equal("invalid", verification.Diagnostics.Result);
+ Assert.Equal("missing", verification.Diagnostics.FailureReason);
+ }
+
+ [Fact]
+ public async Task VerifyAsync_ReturnsInvalid_WhenTransparencyUnavailableAndOfflineDisallowed()
+ {
+ var (request, metadata, envelope) = await CreateSignedAttestationAsync(includeRekor: true);
+ var transparency = new ThrowingTransparencyLogClient();
+ var verifier = CreateVerifier(options =>
+ {
+ options.RequireTransparencyLog = true;
+ options.AllowOfflineTransparency = false;
+ }, transparency);
+
+ var verification = await verifier.VerifyAsync(
+ new VexAttestationVerificationRequest(request, metadata, envelope),
+ CancellationToken.None);
+
+ Assert.False(verification.IsValid);
+ Assert.Equal("unreachable", verification.Diagnostics.RekorState);
+ Assert.Equal("invalid", verification.Diagnostics.Result);
+ Assert.Equal("unreachable", verification.Diagnostics.FailureReason);
}
[Fact]
@@ -125,7 +130,7 @@ public sealed class VexAttestationVerifierTests : IDisposable
CancellationToken.None);
Assert.True(verification.IsValid);
- Assert.Equal("valid", verification.Diagnostics["result"]);
+ Assert.Equal("valid", verification.Diagnostics.Result);
}
[Fact]
@@ -152,6 +157,8 @@ public sealed class VexAttestationVerifierTests : IDisposable
Assert.True(verification.IsValid);
Assert.Equal("verified", verification.Diagnostics["signature.state"]);
+ Assert.Equal("valid", verification.Diagnostics.Result);
+ Assert.Null(verification.Diagnostics.FailureReason);
}
[Fact]
@@ -179,6 +186,8 @@ public sealed class VexAttestationVerifierTests : IDisposable
Assert.False(verification.IsValid);
Assert.Equal("error", verification.Diagnostics["signature.state"]);
Assert.Equal("verification_failed", verification.Diagnostics["signature.reason"]);
+ Assert.Equal("verification_failed", verification.Diagnostics.FailureReason);
+ Assert.Equal("invalid", verification.Diagnostics.Result);
}
private async Task<(VexAttestationRequest Request, VexAttestationMetadata Metadata, string Envelope)> CreateSignedAttestationAsync(
diff --git a/src/Excititor/__Tests/StellaOps.Excititor.Export.Tests/ExportEngineTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.Export.Tests/ExportEngineTests.cs
index 9ede1c936..581e48fc3 100644
--- a/src/Excititor/__Tests/StellaOps.Excititor.Export.Tests/ExportEngineTests.cs
+++ b/src/Excititor/__Tests/StellaOps.Excititor.Export.Tests/ExportEngineTests.cs
@@ -6,6 +6,7 @@ using System.Globalization;
using Microsoft.Extensions.Logging.Abstractions;
using MongoDB.Driver;
using StellaOps.Excititor.Core;
+using StellaOps.Excititor.Attestation.Verification;
using StellaOps.Excititor.Export;
using StellaOps.Excititor.Policy;
using StellaOps.Excititor.Storage.Mongo;
@@ -291,7 +292,7 @@ public sealed class ExportEngineTests
}
public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
- => ValueTask.FromResult(new VexAttestationVerification(true, ImmutableDictionary.Empty));
+ => ValueTask.FromResult(new VexAttestationVerification(true, VexAttestationDiagnostics.Empty));
}
private sealed class RecordingCacheIndex : IVexCacheIndex
diff --git a/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestServiceOverrides.cs b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestServiceOverrides.cs
index 85572f800..2e43bfdb3 100644
--- a/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestServiceOverrides.cs
+++ b/src/Excititor/__Tests/StellaOps.Excititor.WebService.Tests/TestServiceOverrides.cs
@@ -4,13 +4,14 @@ using System.Collections.Immutable;
using System.Text;
using System.Text.Json;
using Microsoft.Extensions.DependencyInjection;
-using Microsoft.Extensions.DependencyInjection.Extensions;
-using Microsoft.Extensions.Hosting;
-using Microsoft.Extensions.Logging;
-using StellaOps.Excititor.Core;
-using StellaOps.Excititor.Export;
-using StellaOps.Excititor.Storage.Mongo;
-using StellaOps.Excititor.WebService.Services;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using StellaOps.Excititor.Core;
+using StellaOps.Excititor.Attestation.Verification;
+using StellaOps.Excititor.Export;
+using StellaOps.Excititor.Storage.Mongo;
+using StellaOps.Excititor.WebService.Services;
using MongoDB.Driver;
using StellaOps.Excititor.Attestation.Dsse;
@@ -162,7 +163,7 @@ internal static class TestServiceOverrides
public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
{
- var verification = new VexAttestationVerification(true, ImmutableDictionary.Empty);
+ var verification = new VexAttestationVerification(true, VexAttestationDiagnostics.Empty);
return ValueTask.FromResult(verification);
}
}
diff --git a/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/DefaultVexProviderRunnerTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/DefaultVexProviderRunnerTests.cs
index b8909851e..6fb193ec5 100644
--- a/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/DefaultVexProviderRunnerTests.cs
+++ b/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/DefaultVexProviderRunnerTests.cs
@@ -504,6 +504,21 @@ public sealed class DefaultVexProviderRunnerTests
bool includeGlobal,
CancellationToken cancellationToken)
=> ValueTask.FromResult(DefaultTrust);
+
+ public ValueTask SetIssuerTrustAsync(
+ string tenantId,
+ string issuerId,
+ decimal weight,
+ string? reason,
+ CancellationToken cancellationToken)
+ => ValueTask.FromResult(DefaultTrust);
+
+ public ValueTask DeleteIssuerTrustAsync(
+ string tenantId,
+ string issuerId,
+ string? reason,
+ CancellationToken cancellationToken)
+ => ValueTask.CompletedTask;
}
private sealed class NoopSignatureVerifier : IVexSignatureVerifier
@@ -655,25 +670,25 @@ public sealed class DefaultVexProviderRunnerTests
}
}
- private sealed class StubAttestationVerifier : IVexAttestationVerifier
- {
- private readonly bool _isValid;
- private readonly ImmutableDictionary _diagnostics;
-
- public StubAttestationVerifier(bool isValid, ImmutableDictionary diagnostics)
- {
- _isValid = isValid;
- _diagnostics = diagnostics;
- }
-
- public int Invocations { get; private set; }
-
- public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
- {
- Invocations++;
- return ValueTask.FromResult(new VexAttestationVerification(_isValid, _diagnostics));
- }
- }
+ private sealed class StubAttestationVerifier : IVexAttestationVerifier
+ {
+ private readonly bool _isValid;
+ private readonly VexAttestationDiagnostics _diagnostics;
+
+ public StubAttestationVerifier(bool isValid, ImmutableDictionary diagnostics)
+ {
+ _isValid = isValid;
+ _diagnostics = VexAttestationDiagnostics.FromBuilder(diagnostics.ToBuilder());
+ }
+
+ public int Invocations { get; private set; }
+
+ public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
+ {
+ Invocations++;
+ return ValueTask.FromResult(new VexAttestationVerification(_isValid, _diagnostics));
+ }
+ }
private static VexRawDocument CreateAttestationRawDocument(DateTimeOffset observedAt)
{
diff --git a/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/Signature/WorkerSignatureVerifierTests.cs b/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/Signature/WorkerSignatureVerifierTests.cs
index 41134ca75..90896c8f8 100644
--- a/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/Signature/WorkerSignatureVerifierTests.cs
+++ b/src/Excititor/__Tests/StellaOps.Excititor.Worker.Tests/Signature/WorkerSignatureVerifierTests.cs
@@ -249,19 +249,21 @@ public sealed class WorkerSignatureVerifierTests
private sealed class StubAttestationVerifier : IVexAttestationVerifier
{
private readonly bool _isValid;
- private readonly ImmutableDictionary _diagnostics;
+ private readonly VexAttestationDiagnostics _diagnostics;
public StubAttestationVerifier(bool isValid, ImmutableDictionary? diagnostics = null)
- {
- _isValid = isValid;
- _diagnostics = diagnostics ?? ImmutableDictionary.Empty;
- }
-
- public int Invocations { get; private set; }
-
- public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
- {
- Invocations++;
+ {
+ _isValid = isValid;
+ _diagnostics = diagnostics is null
+ ? VexAttestationDiagnostics.Empty
+ : VexAttestationDiagnostics.FromBuilder(diagnostics.ToBuilder());
+ }
+
+ public int Invocations { get; private set; }
+
+ public ValueTask VerifyAsync(VexAttestationVerificationRequest request, CancellationToken cancellationToken)
+ {
+ Invocations++;
return ValueTask.FromResult(new VexAttestationVerification(_isValid, _diagnostics));
}
}
@@ -269,7 +271,7 @@ public sealed class WorkerSignatureVerifierTests
private sealed class StubIssuerDirectoryClient : IIssuerDirectoryClient
{
private readonly IReadOnlyList _keys;
- private readonly IssuerTrustResponseModel _trust;
+ private IssuerTrustResponseModel _trust;
private StubIssuerDirectoryClient(
IReadOnlyList keys,
@@ -302,7 +304,7 @@ public sealed class WorkerSignatureVerifierTests
null,
null);
- var now = DateTimeOffset.UtcNow;
+ var now = DateTimeOffset.UnixEpoch;
var overrideModel = new IssuerTrustOverrideModel(weight, "stub", now, "test", now, "test");
return new StubIssuerDirectoryClient(
new[] { key },
@@ -322,6 +324,29 @@ public sealed class WorkerSignatureVerifierTests
bool includeGlobal,
CancellationToken cancellationToken)
=> ValueTask.FromResult(_trust);
+
+ public ValueTask SetIssuerTrustAsync(
+ string tenantId,
+ string issuerId,
+ decimal weight,
+ string? reason,
+ CancellationToken cancellationToken)
+ {
+ var now = DateTimeOffset.UnixEpoch;
+ var overrideModel = new IssuerTrustOverrideModel(weight, "stub-set", now, "test", now, "test");
+ _trust = new IssuerTrustResponseModel(overrideModel, null, weight);
+ return ValueTask.FromResult(_trust);
+ }
+
+ public ValueTask DeleteIssuerTrustAsync(
+ string tenantId,
+ string issuerId,
+ string? reason,
+ CancellationToken cancellationToken)
+ {
+ _trust = new IssuerTrustResponseModel(null, null, 0m);
+ return ValueTask.CompletedTask;
+ }
}
private sealed class FixedTimeProvider : TimeProvider
diff --git a/src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md b/src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md
index 981b0fc97..7edfa294f 100644
--- a/src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md
+++ b/src/ExportCenter/StellaOps.ExportCenter.DevPortalOffline/TASKS.md
@@ -3,5 +3,5 @@
## Sprint 64 – Bundle Implementation
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|----|--------|----------|------------|-------------|---------------|
-| DVOFF-64-001 | DOING (2025-11-04) | DevPortal Offline Guild, Exporter Guild | DEVPORT-64-001, SDKREL-64-002 | Implement Export Center job `devportal --offline` bundling portal HTML, specs, SDK artifacts, changelogs, and verification manifest. | Job executes in staging; manifest contains checksums + DSSE signatures; docs updated. |
+| DVOFF-64-001 | DONE (2025-11-05) | DevPortal Offline Guild, Exporter Guild | DEVPORT-64-001, SDKREL-64-002 | Implement Export Center job `devportal --offline` bundling portal HTML, specs, SDK artifacts, changelogs, and verification manifest. | Job executes in staging; manifest contains checksums + DSSE signatures; docs updated. |
| DVOFF-64-002 | TODO | DevPortal Offline Guild, AirGap Controller Guild | DVOFF-64-001 | Provide verification CLI (`stella devportal verify bundle.tgz`) ensuring integrity before import. | CLI command validates signatures; integration test covers corrupted bundle; runbook updated. |
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineJob.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineJob.cs
new file mode 100644
index 000000000..5826a4ec5
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineJob.cs
@@ -0,0 +1,176 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace StellaOps.ExportCenter.Core.DevPortalOffline;
+
+///
+/// Coordinates bundle construction, manifest signing, and artefact persistence for the devportal offline export.
+///
+public sealed class DevPortalOfflineJob
+{
+ private static readonly JsonSerializerOptions SignatureSerializerOptions = new(JsonSerializerDefaults.Web)
+ {
+ WriteIndented = true
+ };
+
+ private readonly DevPortalOfflineBundleBuilder _builder;
+ private readonly IDevPortalOfflineObjectStore _objectStore;
+ private readonly IDevPortalOfflineManifestSigner _manifestSigner;
+ private readonly ILogger _logger;
+
+ public DevPortalOfflineJob(
+ DevPortalOfflineBundleBuilder builder,
+ IDevPortalOfflineObjectStore objectStore,
+ IDevPortalOfflineManifestSigner manifestSigner,
+ ILogger logger)
+ {
+ _builder = builder ?? throw new ArgumentNullException(nameof(builder));
+ _objectStore = objectStore ?? throw new ArgumentNullException(nameof(objectStore));
+ _manifestSigner = manifestSigner ?? throw new ArgumentNullException(nameof(manifestSigner));
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ public async Task ExecuteAsync(
+ DevPortalOfflineJobRequest request,
+ CancellationToken cancellationToken = default)
+ {
+ ArgumentNullException.ThrowIfNull(request);
+
+ cancellationToken.ThrowIfCancellationRequested();
+
+ var bundleResult = _builder.Build(request.BundleRequest, cancellationToken);
+ _logger.LogInformation("DevPortal offline bundle constructed with {EntryCount} entries.", bundleResult.Manifest.Entries.Count);
+
+ var signature = await _manifestSigner.SignAsync(
+ request.BundleRequest.BundleId,
+ bundleResult.ManifestJson,
+ bundleResult.RootHash,
+ cancellationToken).ConfigureAwait(false);
+
+ var storagePrefix = BuildStoragePrefix(request.StoragePrefix, request.BundleRequest.BundleId);
+ var bundleFileName = SanitizeFileName(request.BundleFileName);
+
+ var manifestKey = $"{storagePrefix}/manifest.json";
+ var signatureKey = $"{storagePrefix}/manifest.dsse.json";
+ var checksumsKey = $"{storagePrefix}/checksums.txt";
+ var bundleKey = $"{storagePrefix}/{bundleFileName}";
+
+ var manifestMetadata = await StoreTextAsync(
+ bundleResult.ManifestJson,
+ manifestKey,
+ MediaTypes.Json,
+ cancellationToken).ConfigureAwait(false);
+
+ var signatureJson = JsonSerializer.Serialize(signature, SignatureSerializerOptions);
+ var signatureMetadata = await StoreTextAsync(
+ signatureJson,
+ signatureKey,
+ MediaTypes.Json,
+ cancellationToken).ConfigureAwait(false);
+
+ var checksumsMetadata = await StoreTextAsync(
+ bundleResult.Checksums,
+ checksumsKey,
+ MediaTypes.Text,
+ cancellationToken).ConfigureAwait(false);
+
+ DevPortalOfflineStorageMetadata bundleMetadata;
+ using (bundleResult.BundleStream)
+ {
+ bundleResult.BundleStream.Position = 0;
+ bundleMetadata = await _objectStore.StoreAsync(
+ bundleResult.BundleStream,
+ new DevPortalOfflineObjectStoreOptions(bundleKey, MediaTypes.GZip),
+ cancellationToken).ConfigureAwait(false);
+ }
+
+ _logger.LogInformation(
+ "DevPortal offline bundle stored at {BundleKey} ({SizeBytes} bytes).",
+ bundleMetadata.StorageKey,
+ bundleMetadata.SizeBytes);
+
+ return new DevPortalOfflineJobOutcome(
+ bundleResult.Manifest,
+ bundleResult.RootHash,
+ signature,
+ manifestMetadata,
+ signatureMetadata,
+ checksumsMetadata,
+ bundleMetadata);
+ }
+
+ private Task StoreTextAsync(
+ string content,
+ string storageKey,
+ string contentType,
+ CancellationToken cancellationToken)
+ {
+ var bytes = Encoding.UTF8.GetBytes(content);
+ var stream = new MemoryStream(bytes, writable: false);
+ return StoreAsync(stream, storageKey, contentType, cancellationToken);
+ }
+
+ private async Task StoreAsync(
+ Stream stream,
+ string storageKey,
+ string contentType,
+ CancellationToken cancellationToken)
+ {
+ try
+ {
+ return await _objectStore.StoreAsync(
+ stream,
+ new DevPortalOfflineObjectStoreOptions(storageKey, contentType),
+ cancellationToken)
+ .ConfigureAwait(false);
+ }
+ finally
+ {
+ await stream.DisposeAsync().ConfigureAwait(false);
+ }
+ }
+
+ private static string BuildStoragePrefix(string? prefix, Guid bundleId)
+ {
+ var trimmed = string.IsNullOrWhiteSpace(prefix)
+ ? string.Empty
+ : prefix.Trim().Trim('/').Replace('\\', '/');
+
+ return string.IsNullOrEmpty(trimmed)
+ ? bundleId.ToString("D")
+ : $"{trimmed}/{bundleId:D}";
+ }
+
+ private static string SanitizeFileName(string? value)
+ {
+ if (string.IsNullOrWhiteSpace(value))
+ {
+ return "devportal-offline-bundle.tgz";
+ }
+
+ var fileName = Path.GetFileName(value);
+ if (string.IsNullOrEmpty(fileName))
+ {
+ return "devportal-offline-bundle.tgz";
+ }
+
+ if (fileName.Contains("..", StringComparison.Ordinal))
+ {
+ throw new InvalidOperationException("Bundle file name cannot contain path traversal sequences.");
+ }
+
+ return fileName;
+ }
+
+ private static class MediaTypes
+ {
+ public const string Json = "application/json";
+ public const string Text = "text/plain";
+ public const string GZip = "application/gzip";
+ }
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineJobModels.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineJobModels.cs
new file mode 100644
index 000000000..a2ecd8ae3
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineJobModels.cs
@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+
+namespace StellaOps.ExportCenter.Core.DevPortalOffline;
+
+///
+/// Represents the inputs required to execute the devportal offline export job.
+///
+/// Bundle builder request describing source directories and bundle metadata.
+/// Relative storage prefix (without bundle identifier) where artefacts are persisted.
+/// File name used for the packaged archive in storage.
+public sealed record DevPortalOfflineJobRequest(
+ DevPortalOfflineBundleRequest BundleRequest,
+ string StoragePrefix,
+ string BundleFileName);
+
+///
+/// Captures metadata produced after successfully executing the devportal offline export job.
+///
+/// The manifest describing bundled artefacts.
+/// SHA-256 hash of the manifest JSON payload.
+/// DSSE envelope and metadata for the manifest.
+/// Storage metadata for the manifest JSON artefact.
+/// Storage metadata for the manifest signature document.
+/// Storage metadata for the checksum file.
+/// Storage metadata for the bundled archive.
+public sealed record DevPortalOfflineJobOutcome(
+ DevPortalOfflineBundleManifest Manifest,
+ string RootHash,
+ DevPortalOfflineManifestSignatureDocument Signature,
+ DevPortalOfflineStorageMetadata ManifestStorage,
+ DevPortalOfflineStorageMetadata SignatureStorage,
+ DevPortalOfflineStorageMetadata ChecksumsStorage,
+ DevPortalOfflineStorageMetadata BundleStorage);
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineManifestSignature.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineManifestSignature.cs
new file mode 100644
index 000000000..2498a2b54
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/DevPortalOffline/DevPortalOfflineManifestSignature.cs
@@ -0,0 +1,56 @@
+using System;
+using System.Collections.Generic;
+using System.Text.Json.Serialization;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace StellaOps.ExportCenter.Core.DevPortalOffline;
+
+///
+/// Provides DSSE signing for devportal offline bundle manifests.
+///
+public interface IDevPortalOfflineManifestSigner
+{
+ Task SignAsync(
+ Guid bundleId,
+ string manifestJson,
+ string rootHash,
+ CancellationToken cancellationToken = default);
+}
+
+///
+/// DSSE signature document emitted for devportal manifest verification.
+///
+/// Identifier of the bundle being signed.
+/// SHA-256 hash of the manifest JSON.
+/// UTC timestamp when the signature was created.
+/// Signing algorithm identifier (for example HMACSHA256).
+/// Identifier of the signing key.
+/// DSSE envelope containing payload and signatures.
+public sealed record DevPortalOfflineManifestSignatureDocument(
+ [property: JsonPropertyName("bundleId")] Guid BundleId,
+ [property: JsonPropertyName("rootHash")] string RootHash,
+ [property: JsonPropertyName("signedAt")] DateTimeOffset SignedAtUtc,
+ [property: JsonPropertyName("algorithm")] string Algorithm,
+ [property: JsonPropertyName("keyId")] string KeyId,
+ [property: JsonPropertyName("envelope")] DevPortalOfflineManifestDsseEnvelope Envelope);
+
+///
+/// Standard DSSE envelope carrying payload and signatures.
+///
+/// Type of the payload (for example application/json).
+/// Base64-encoded manifest payload.
+/// Collection of DSSE signatures.
+public sealed record DevPortalOfflineManifestDsseEnvelope(
+ [property: JsonPropertyName("payloadType")] string PayloadType,
+ [property: JsonPropertyName("payload")] string Payload,
+ [property: JsonPropertyName("signatures")] IReadOnlyList Signatures);
+
+///
+/// Represents an individual DSSE signature entry.
+///
+/// Base64-encoded signature.
+/// Identifier for the key used to sign.
+public sealed record DevPortalOfflineManifestDsseSignature(
+ [property: JsonPropertyName("sig")] string Signature,
+ [property: JsonPropertyName("keyid")] string? KeyId);
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/StellaOps.ExportCenter.Core.csproj b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/StellaOps.ExportCenter.Core.csproj
index e4808f0d8..032c5eebc 100644
--- a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/StellaOps.ExportCenter.Core.csproj
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Core/StellaOps.ExportCenter.Core.csproj
@@ -3,16 +3,15 @@
-
-
-
- net10.0
- enable
- enable
- preview
- true
-
-
-
-
+
+ net10.0
+ enable
+ enable
+ preview
+ true
+
+
+
+
+
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/DevPortalOfflineManifestSigningOptions.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/DevPortalOfflineManifestSigningOptions.cs
new file mode 100644
index 000000000..aa7e046a6
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/DevPortalOfflineManifestSigningOptions.cs
@@ -0,0 +1,18 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace StellaOps.ExportCenter.Infrastructure.DevPortalOffline;
+
+public sealed class DevPortalOfflineManifestSigningOptions
+{
+ [Required]
+ public string KeyId { get; set; } = "devportal-offline-local";
+
+ [Required]
+ public string Secret { get; set; } = null!;
+
+ [Required]
+ public string Algorithm { get; set; } = "HMACSHA256";
+
+ [Required]
+ public string PayloadType { get; set; } = "application/vnd.stella.devportal.manifest+json";
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/DevPortalOfflineStorageOptions.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/DevPortalOfflineStorageOptions.cs
new file mode 100644
index 000000000..411dcf19d
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/DevPortalOfflineStorageOptions.cs
@@ -0,0 +1,9 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace StellaOps.ExportCenter.Infrastructure.DevPortalOffline;
+
+public sealed class DevPortalOfflineStorageOptions
+{
+ [Required]
+ public string RootPath { get; set; } = null!;
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/FileSystemDevPortalOfflineObjectStore.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/FileSystemDevPortalOfflineObjectStore.cs
new file mode 100644
index 000000000..b1e4be6b7
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/FileSystemDevPortalOfflineObjectStore.cs
@@ -0,0 +1,149 @@
+using System;
+using System.Buffers;
+using System.IO;
+using System.Security.Cryptography;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StellaOps.ExportCenter.Core.DevPortalOffline;
+
+namespace StellaOps.ExportCenter.Infrastructure.DevPortalOffline;
+
+public sealed class FileSystemDevPortalOfflineObjectStore : IDevPortalOfflineObjectStore
+{
+ private readonly IOptionsMonitor _options;
+ private readonly TimeProvider _timeProvider;
+ private readonly ILogger _logger;
+
+ public FileSystemDevPortalOfflineObjectStore(
+ IOptionsMonitor options,
+ TimeProvider timeProvider,
+ ILogger logger)
+ {
+ _options = options ?? throw new ArgumentNullException(nameof(options));
+ _timeProvider = timeProvider ?? TimeProvider.System;
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ public async Task StoreAsync(
+ Stream content,
+ DevPortalOfflineObjectStoreOptions storeOptions,
+ CancellationToken cancellationToken)
+ {
+ ArgumentNullException.ThrowIfNull(content);
+ ArgumentNullException.ThrowIfNull(storeOptions);
+
+ var root = EnsureRootPath();
+ var storageKey = SanitizeKey(storeOptions.StorageKey);
+ var fullPath = GetFullPath(root, storageKey);
+ Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
+
+ content.Seek(0, SeekOrigin.Begin);
+ using var fileStream = new FileStream(fullPath, FileMode.Create, FileAccess.Write, FileShare.None);
+ using var hash = IncrementalHash.CreateHash(HashAlgorithmName.SHA256);
+ var buffer = ArrayPool.Shared.Rent(128 * 1024);
+ long totalBytes = 0;
+
+ try
+ {
+ int read;
+ while ((read = await content.ReadAsync(buffer.AsMemory(0, buffer.Length), cancellationToken).ConfigureAwait(false)) > 0)
+ {
+ await fileStream.WriteAsync(buffer.AsMemory(0, read), cancellationToken).ConfigureAwait(false);
+ hash.AppendData(buffer, 0, read);
+ totalBytes += read;
+ }
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(buffer);
+ }
+
+ await fileStream.FlushAsync(cancellationToken).ConfigureAwait(false);
+ content.Seek(0, SeekOrigin.Begin);
+
+ var sha = Convert.ToHexString(hash.GetHashAndReset()).ToLowerInvariant();
+ var createdAt = _timeProvider.GetUtcNow();
+
+ _logger.LogDebug("Stored devportal artefact at {Path} ({Bytes} bytes).", fullPath, totalBytes);
+
+ return new DevPortalOfflineStorageMetadata(
+ storageKey,
+ storeOptions.ContentType,
+ totalBytes,
+ sha,
+ createdAt);
+ }
+
+ public Task ExistsAsync(string storageKey, CancellationToken cancellationToken)
+ {
+ var root = EnsureRootPath();
+ var fullPath = GetFullPath(root, SanitizeKey(storageKey));
+ var exists = File.Exists(fullPath);
+ return Task.FromResult(exists);
+ }
+
+ public Task OpenReadAsync(string storageKey, CancellationToken cancellationToken)
+ {
+ var root = EnsureRootPath();
+ var fullPath = GetFullPath(root, SanitizeKey(storageKey));
+ if (!File.Exists(fullPath))
+ {
+ throw new FileNotFoundException($"DevPortal offline artefact '{storageKey}' was not found.", fullPath);
+ }
+
+ Stream stream = new FileStream(fullPath, FileMode.Open, FileAccess.Read, FileShare.Read);
+ return Task.FromResult(stream);
+ }
+
+ private string EnsureRootPath()
+ {
+ var root = _options.CurrentValue.RootPath;
+ if (string.IsNullOrWhiteSpace(root))
+ {
+ throw new InvalidOperationException("DevPortal offline storage root path is not configured.");
+ }
+
+ var full = Path.GetFullPath(root);
+ if (!Directory.Exists(full))
+ {
+ Directory.CreateDirectory(full);
+ }
+
+ if (!full.EndsWith(Path.DirectorySeparatorChar))
+ {
+ full += Path.DirectorySeparatorChar;
+ }
+
+ return full;
+ }
+
+ private static string SanitizeKey(string storageKey)
+ {
+ if (string.IsNullOrWhiteSpace(storageKey))
+ {
+ throw new ArgumentException("Storage key cannot be empty.", nameof(storageKey));
+ }
+
+ if (storageKey.Contains("..", StringComparison.Ordinal))
+ {
+ throw new ArgumentException("Storage key cannot contain path traversal sequences.", nameof(storageKey));
+ }
+
+ var trimmed = storageKey.Trim().Trim('/').Replace('\\', '/');
+ return trimmed;
+ }
+
+ private static string GetFullPath(string root, string storageKey)
+ {
+ var combined = Path.Combine(root, storageKey.Replace('/', Path.DirectorySeparatorChar));
+ var fullPath = Path.GetFullPath(combined);
+ if (!fullPath.StartsWith(root, StringComparison.Ordinal))
+ {
+ throw new InvalidOperationException("Storage key resolves outside of configured root path.");
+ }
+
+ return fullPath;
+ }
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/HmacDevPortalOfflineManifestSigner.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/HmacDevPortalOfflineManifestSigner.cs
new file mode 100644
index 000000000..fe11a4db8
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/DevPortalOffline/HmacDevPortalOfflineManifestSigner.cs
@@ -0,0 +1,121 @@
+using System;
+using System.Buffers.Binary;
+using System.ComponentModel.DataAnnotations;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StellaOps.ExportCenter.Core.DevPortalOffline;
+
+namespace StellaOps.ExportCenter.Infrastructure.DevPortalOffline;
+
+public sealed class HmacDevPortalOfflineManifestSigner : IDevPortalOfflineManifestSigner
+{
+ private readonly IOptionsMonitor _options;
+ private readonly TimeProvider _timeProvider;
+ private readonly ILogger _logger;
+
+ public HmacDevPortalOfflineManifestSigner(
+ IOptionsMonitor options,
+ TimeProvider timeProvider,
+ ILogger logger)
+ {
+ _options = options ?? throw new ArgumentNullException(nameof(options));
+ _timeProvider = timeProvider ?? TimeProvider.System;
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ }
+
+ public Task SignAsync(
+ Guid bundleId,
+ string manifestJson,
+ string rootHash,
+ CancellationToken cancellationToken = default)
+ {
+ if (string.IsNullOrWhiteSpace(manifestJson))
+ {
+ throw new ArgumentException("Manifest JSON is required.", nameof(manifestJson));
+ }
+
+ if (string.IsNullOrWhiteSpace(rootHash))
+ {
+ throw new ArgumentException("Root hash is required.", nameof(rootHash));
+ }
+
+ var options = _options.CurrentValue;
+ ValidateOptions(options);
+
+ var signedAt = _timeProvider.GetUtcNow();
+ var payloadBytes = Encoding.UTF8.GetBytes(manifestJson);
+ var pae = BuildPreAuthEncoding(options.PayloadType, payloadBytes);
+ var signature = ComputeSignature(options, pae);
+ var payloadBase64 = Convert.ToBase64String(payloadBytes);
+
+ _logger.LogDebug("Signed devportal manifest for bundle {BundleId}.", bundleId);
+
+ var envelope = new DevPortalOfflineManifestDsseEnvelope(
+ options.PayloadType,
+ payloadBase64,
+ new[]
+ {
+ new DevPortalOfflineManifestDsseSignature(signature, options.KeyId)
+ });
+
+ var document = new DevPortalOfflineManifestSignatureDocument(
+ bundleId,
+ rootHash,
+ signedAt,
+ options.Algorithm,
+ options.KeyId,
+ envelope);
+
+ return Task.FromResult(document);
+ }
+
+ private static void ValidateOptions(DevPortalOfflineManifestSigningOptions options)
+ {
+ Validator.ValidateObject(options, new ValidationContext(options), validateAllProperties: true);
+ if (!string.Equals(options.Algorithm, "HMACSHA256", StringComparison.OrdinalIgnoreCase))
+ {
+ throw new NotSupportedException($"Algorithm '{options.Algorithm}' is not supported for devportal manifest signing.");
+ }
+ }
+
+ private static string ComputeSignature(DevPortalOfflineManifestSigningOptions options, byte[] pae)
+ {
+ var secretBytes = Convert.FromBase64String(options.Secret);
+ using var hmac = new HMACSHA256(secretBytes);
+ var signatureBytes = hmac.ComputeHash(pae);
+ return Convert.ToBase64String(signatureBytes);
+ }
+
+ private static byte[] BuildPreAuthEncoding(string payloadType, byte[] payloadBytes)
+ {
+ var typeBytes = Encoding.UTF8.GetBytes(payloadType ?? string.Empty);
+ const string prefix = "DSSEv1";
+
+ var totalLength = prefix.Length +
+ sizeof(ulong) +
+ sizeof(ulong) + typeBytes.Length +
+ sizeof(ulong) + payloadBytes.Length;
+
+ var buffer = new byte[totalLength];
+ var span = buffer.AsSpan();
+
+ var offset = Encoding.UTF8.GetBytes(prefix, span);
+ BinaryPrimitives.WriteUInt64BigEndian(span[offset..], 2);
+ offset += sizeof(ulong);
+
+ BinaryPrimitives.WriteUInt64BigEndian(span[offset..], (ulong)typeBytes.Length);
+ offset += sizeof(ulong);
+ typeBytes.CopyTo(span[offset..]);
+ offset += typeBytes.Length;
+
+ BinaryPrimitives.WriteUInt64BigEndian(span[offset..], (ulong)payloadBytes.Length);
+ offset += sizeof(ulong);
+ payloadBytes.CopyTo(span[offset..]);
+
+ return buffer;
+ }
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/StellaOps.ExportCenter.Infrastructure.csproj b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/StellaOps.ExportCenter.Infrastructure.csproj
index fcc97aea8..dca48658b 100644
--- a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/StellaOps.ExportCenter.Infrastructure.csproj
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Infrastructure/StellaOps.ExportCenter.Infrastructure.csproj
@@ -1,28 +1,19 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- net10.0
- enable
- enable
- preview
- true
-
-
-
-
-
+
+
+
+ net10.0
+ enable
+ enable
+ preview
+ true
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineBundleBuilderTests.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineBundleBuilderTests.cs
index d47c7f5e9..b5b5e0eb8 100644
--- a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineBundleBuilderTests.cs
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineBundleBuilderTests.cs
@@ -52,7 +52,7 @@ public sealed class DevPortalOfflineBundleBuilderTests
var fixedNow = new DateTimeOffset(2025, 11, 4, 12, 30, 0, TimeSpan.Zero);
var builder = new DevPortalOfflineBundleBuilder(new FixedTimeProvider(fixedNow));
- var result = builder.Build(request);
+ var result = builder.Build(request, TestContext.Current.CancellationToken);
Assert.Equal(request.BundleId, result.Manifest.BundleId);
Assert.Equal("devportal-offline/v1", result.Manifest.Version);
@@ -65,12 +65,12 @@ public sealed class DevPortalOfflineBundleBuilderTests
var expectedPaths = new[]
{
+ "changelog/CHANGELOG.md",
"portal/assets/app.js",
"portal/index.html",
- "specs/openapi.yaml",
"sdks/dotnet/stellaops.sdk.nupkg",
"sdks/python/stellaops_sdk.whl",
- "changelog/CHANGELOG.md"
+ "specs/openapi.yaml"
};
Assert.Equal(expectedPaths, result.Manifest.Entries.Select(entry => entry.Path).ToArray());
@@ -119,7 +119,10 @@ public sealed class DevPortalOfflineBundleBuilderTests
}
finally
{
- tempRoot.Dispose();
+ if (Directory.Exists(tempRoot.FullName))
+ {
+ Directory.Delete(tempRoot.FullName, recursive: true);
+ }
}
}
@@ -129,7 +132,7 @@ public sealed class DevPortalOfflineBundleBuilderTests
var builder = new DevPortalOfflineBundleBuilder(new FixedTimeProvider(DateTimeOffset.UtcNow));
var request = new DevPortalOfflineBundleRequest(Guid.NewGuid());
- var exception = Assert.Throws(() => builder.Build(request));
+ var exception = Assert.Throws(() => builder.Build(request, TestContext.Current.CancellationToken));
Assert.Contains("does not contain any files", exception.Message, StringComparison.Ordinal);
}
@@ -145,7 +148,7 @@ public sealed class DevPortalOfflineBundleBuilderTests
File.WriteAllText(Path.Combine(portalRoot, "index.html"), "");
var builder = new DevPortalOfflineBundleBuilder(new FixedTimeProvider(DateTimeOffset.UtcNow));
- var result = builder.Build(new DevPortalOfflineBundleRequest(Guid.NewGuid(), portalRoot));
+ var result = builder.Build(new DevPortalOfflineBundleRequest(Guid.NewGuid(), portalRoot), TestContext.Current.CancellationToken);
Assert.Single(result.Manifest.Entries);
Assert.True(result.Manifest.Sources.PortalIncluded);
@@ -155,7 +158,10 @@ public sealed class DevPortalOfflineBundleBuilderTests
}
finally
{
- tempRoot.Dispose();
+ if (Directory.Exists(tempRoot.FullName))
+ {
+ Directory.Delete(tempRoot.FullName, recursive: true);
+ }
}
}
@@ -166,7 +172,7 @@ public sealed class DevPortalOfflineBundleBuilderTests
var missing = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N"));
var request = new DevPortalOfflineBundleRequest(Guid.NewGuid(), missing);
- Assert.Throws(() => builder.Build(request));
+ Assert.Throws(() => builder.Build(request, TestContext.Current.CancellationToken));
}
private static string CalculateFileHash(string path)
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineJobTests.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineJobTests.cs
new file mode 100644
index 000000000..f1aea25f0
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/DevPortalOfflineJobTests.cs
@@ -0,0 +1,217 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography;
+using System.Text;
+using System.Text.Json;
+using System.Threading;
+using System.Threading.Tasks;
+using StellaOps.ExportCenter.Core.DevPortalOffline;
+using Microsoft.Extensions.Logging.Abstractions;
+
+namespace StellaOps.ExportCenter.Tests;
+
+public class DevPortalOfflineJobTests
+{
+ [Fact]
+ public async Task ExecuteAsync_StoresArtefacts()
+ {
+ var tempRoot = Directory.CreateTempSubdirectory();
+ try
+ {
+ var portalRoot = Path.Combine(tempRoot.FullName, "portal");
+ Directory.CreateDirectory(portalRoot);
+ File.WriteAllText(Path.Combine(portalRoot, "index.html"), "offline");
+
+ var specsRoot = Path.Combine(tempRoot.FullName, "specs");
+ Directory.CreateDirectory(specsRoot);
+ File.WriteAllText(Path.Combine(specsRoot, "api.json"), "{\"openapi\":\"3.1.0\"}");
+
+ var sdkRoot = Path.Combine(tempRoot.FullName, "sdk-dotnet");
+ Directory.CreateDirectory(sdkRoot);
+ File.WriteAllText(Path.Combine(sdkRoot, "stellaops.sdk.nupkg"), "binary");
+
+ var changelogRoot = Path.Combine(tempRoot.FullName, "changelog");
+ Directory.CreateDirectory(changelogRoot);
+ File.WriteAllText(Path.Combine(changelogRoot, "CHANGELOG.md"), "# 2025.11.0");
+
+ var bundleId = Guid.Parse("5e76bb6f-2925-41ea-8e72-1fd8a384dd1a");
+ var request = new DevPortalOfflineBundleRequest(
+ bundleId,
+ portalRoot,
+ specsRoot,
+ new[] { new DevPortalSdkSource("dotnet", sdkRoot) },
+ changelogRoot,
+ new Dictionary { ["releaseVersion"] = "2025.11.0" });
+
+ var fixedNow = new DateTimeOffset(2025, 11, 4, 18, 15, 0, TimeSpan.Zero);
+ var timeProvider = new FixedTimeProvider(fixedNow);
+ var builder = new DevPortalOfflineBundleBuilder(timeProvider);
+ var objectStore = new InMemoryObjectStore(timeProvider);
+ var signer = new TestManifestSigner(timeProvider);
+ var job = new DevPortalOfflineJob(builder, objectStore, signer, NullLogger.Instance);
+
+ var outcome = await job.ExecuteAsync(
+ new DevPortalOfflineJobRequest(request, "exports/devportal", "bundle.tgz"),
+ TestContext.Current.CancellationToken);
+
+ var expectedPrefix = $"exports/devportal/{bundleId:D}";
+ Assert.Equal($"{expectedPrefix}/manifest.json", outcome.ManifestStorage.StorageKey);
+ Assert.Equal($"{expectedPrefix}/manifest.dsse.json", outcome.SignatureStorage.StorageKey);
+ Assert.Equal($"{expectedPrefix}/checksums.txt", outcome.ChecksumsStorage.StorageKey);
+ Assert.Equal($"{expectedPrefix}/bundle.tgz", outcome.BundleStorage.StorageKey);
+
+ var manifestText = objectStore.GetText(outcome.ManifestStorage.StorageKey);
+ using (var manifestDoc = JsonDocument.Parse(manifestText))
+ {
+ Assert.Equal("devportal-offline/v1", manifestDoc.RootElement.GetProperty("version").GetString());
+ Assert.Equal("2025.11.0", manifestDoc.RootElement.GetProperty("metadata").GetProperty("releaseVersion").GetString());
+ }
+
+ var signatureText = objectStore.GetText(outcome.SignatureStorage.StorageKey);
+ Assert.Contains(bundleId.ToString("D"), signatureText, StringComparison.OrdinalIgnoreCase);
+ Assert.Contains(outcome.RootHash, signatureText, StringComparison.Ordinal);
+ }
+ finally
+ {
+ if (Directory.Exists(tempRoot.FullName))
+ {
+ Directory.Delete(tempRoot.FullName, recursive: true);
+ }
+ }
+ }
+
+ [Fact]
+ public async Task ExecuteAsync_SanitizesBundleFileName()
+ {
+ var builder = new DevPortalOfflineBundleBuilder(new FixedTimeProvider(DateTimeOffset.UtcNow));
+ var objectStore = new InMemoryObjectStore(new FixedTimeProvider(DateTimeOffset.UtcNow));
+ var signer = new TestManifestSigner(new FixedTimeProvider(DateTimeOffset.UtcNow));
+ var job = new DevPortalOfflineJob(builder, objectStore, signer, NullLogger.Instance);
+
+ var tempRoot = Directory.CreateTempSubdirectory();
+ try
+ {
+ var portalRoot = Path.Combine(tempRoot.FullName, "portal");
+ Directory.CreateDirectory(portalRoot);
+ File.WriteAllText(Path.Combine(portalRoot, "index.html"), "");
+
+ var request = new DevPortalOfflineBundleRequest(Guid.NewGuid(), portalRoot);
+ var outcome = await job.ExecuteAsync(
+ new DevPortalOfflineJobRequest(request, "exports", "../bundle.tgz"),
+ TestContext.Current.CancellationToken);
+
+ var expectedPrefix = $"exports/{request.BundleId:D}";
+ Assert.Equal($"{expectedPrefix}/bundle.tgz", outcome.BundleStorage.StorageKey);
+ }
+ finally
+ {
+ if (Directory.Exists(tempRoot.FullName))
+ {
+ Directory.Delete(tempRoot.FullName, recursive: true);
+ }
+ }
+ }
+
+ private sealed class InMemoryObjectStore : IDevPortalOfflineObjectStore
+ {
+ private readonly Dictionary _entries = new(StringComparer.Ordinal);
+ private readonly TimeProvider _timeProvider;
+
+ public InMemoryObjectStore(TimeProvider timeProvider)
+ {
+ _timeProvider = timeProvider;
+ }
+
+ public Task StoreAsync(
+ Stream content,
+ DevPortalOfflineObjectStoreOptions options,
+ CancellationToken cancellationToken)
+ {
+ using var memory = new MemoryStream();
+ content.CopyTo(memory);
+ var bytes = memory.ToArray();
+ content.Seek(0, SeekOrigin.Begin);
+
+ var sha = Convert.ToHexString(SHA256.HashData(bytes)).ToLowerInvariant();
+ var metadata = new DevPortalOfflineStorageMetadata(
+ options.StorageKey,
+ options.ContentType,
+ bytes.Length,
+ sha,
+ _timeProvider.GetUtcNow());
+
+ _entries[options.StorageKey] = new InMemoryEntry(options.ContentType, bytes);
+ return Task.FromResult(metadata);
+ }
+
+ public Task ExistsAsync(string storageKey, CancellationToken cancellationToken)
+ => Task.FromResult(_entries.ContainsKey(storageKey));
+
+ public Task OpenReadAsync(string storageKey, CancellationToken cancellationToken)
+ {
+ if (!_entries.TryGetValue(storageKey, out var entry))
+ {
+ throw new FileNotFoundException(storageKey);
+ }
+
+ Stream stream = new MemoryStream(entry.Content, writable: false);
+ return Task.FromResult(stream);
+ }
+
+ public string GetText(string storageKey)
+ {
+ if (!_entries.TryGetValue(storageKey, out var entry))
+ {
+ throw new FileNotFoundException(storageKey);
+ }
+
+ return Encoding.UTF8.GetString(entry.Content);
+ }
+
+ private sealed record InMemoryEntry(string ContentType, byte[] Content);
+ }
+
+ private sealed class TestManifestSigner : IDevPortalOfflineManifestSigner
+ {
+ private readonly TimeProvider _timeProvider;
+
+ public TestManifestSigner(TimeProvider timeProvider)
+ {
+ _timeProvider = timeProvider;
+ }
+
+ public Task SignAsync(
+ Guid bundleId,
+ string manifestJson,
+ string rootHash,
+ CancellationToken cancellationToken = default)
+ {
+ var payload = Convert.ToBase64String(Encoding.UTF8.GetBytes(manifestJson));
+ return Task.FromResult(new DevPortalOfflineManifestSignatureDocument(
+ bundleId,
+ rootHash,
+ _timeProvider.GetUtcNow(),
+ "TEST-SHA256",
+ "test-key",
+ new DevPortalOfflineManifestDsseEnvelope(
+ "application/json",
+ payload,
+ new[] { new DevPortalOfflineManifestDsseSignature("c2lnbmF0dXJl", "test-key") })));
+ }
+ }
+
+ private sealed class FixedTimeProvider : TimeProvider
+ {
+ private readonly DateTimeOffset _utcNow;
+
+ public FixedTimeProvider(DateTimeOffset utcNow)
+ {
+ _utcNow = utcNow;
+ }
+
+ public override DateTimeOffset GetUtcNow() => _utcNow;
+
+ public override long GetTimestamp() => TimeProvider.System.GetTimestamp();
+ }
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/HmacDevPortalOfflineManifestSignerTests.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/HmacDevPortalOfflineManifestSignerTests.cs
new file mode 100644
index 000000000..37f8c586d
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Tests/HmacDevPortalOfflineManifestSignerTests.cs
@@ -0,0 +1,147 @@
+using System;
+using System.Buffers.Binary;
+using System.Security.Cryptography;
+using System.Threading;
+using System.Text;
+using Microsoft.Extensions.Logging.Abstractions;
+using Microsoft.Extensions.Options;
+using StellaOps.ExportCenter.Core.DevPortalOffline;
+using StellaOps.ExportCenter.Infrastructure.DevPortalOffline;
+
+namespace StellaOps.ExportCenter.Tests;
+
+public class HmacDevPortalOfflineManifestSignerTests
+{
+ [Fact]
+ public async Task SignAsync_ComputesDeterministicSignature()
+ {
+ var options = new DevPortalOfflineManifestSigningOptions
+ {
+ KeyId = "devportal-test",
+ Secret = Convert.ToBase64String(Encoding.UTF8.GetBytes("shared-secret")),
+ Algorithm = "HMACSHA256",
+ PayloadType = "application/vnd.stella.devportal.manifest+json"
+ };
+
+ var now = new DateTimeOffset(2025, 11, 4, 19, 0, 0, TimeSpan.Zero);
+ var signer = new HmacDevPortalOfflineManifestSigner(
+ new StaticOptionsMonitor(options),
+ new FixedTimeProvider(now),
+ NullLogger.Instance);
+
+ const string manifest = "{\"version\":\"v1\",\"entries\":[]}";
+ var rootHash = Convert.ToHexString(SHA256.HashData(Encoding.UTF8.GetBytes(manifest))).ToLowerInvariant();
+ var bundleId = Guid.Parse("9ca2aafb-42b7-4df9-85f7-5a1d46c4e0ef");
+
+ var document = await signer.SignAsync(bundleId, manifest, rootHash, TestContext.Current.CancellationToken);
+
+ Assert.Equal(bundleId, document.BundleId);
+ Assert.Equal(rootHash, document.RootHash);
+ Assert.Equal(now, document.SignedAtUtc);
+ Assert.Equal(options.Algorithm, document.Algorithm);
+ Assert.Equal(options.KeyId, document.KeyId);
+ Assert.Equal(Convert.ToBase64String(Encoding.UTF8.GetBytes(manifest)), document.Envelope.Payload);
+ Assert.Equal(options.PayloadType, document.Envelope.PayloadType);
+
+ var signature = Assert.Single(document.Envelope.Signatures);
+ Assert.Equal(options.KeyId, signature.KeyId);
+
+ var expectedSignature = ComputeExpectedSignature(options, manifest);
+ Assert.Equal(expectedSignature, signature.Signature);
+ }
+
+ [Fact]
+ public async Task SignAsync_ThrowsForUnsupportedAlgorithm()
+ {
+ var options = new DevPortalOfflineManifestSigningOptions
+ {
+ KeyId = "devportal-test",
+ Secret = Convert.ToBase64String(Encoding.UTF8.GetBytes("shared-secret")),
+ Algorithm = "RSA",
+ PayloadType = "application/json"
+ };
+
+ var signer = new HmacDevPortalOfflineManifestSigner(
+ new StaticOptionsMonitor(options),
+ new FixedTimeProvider(DateTimeOffset.UtcNow),
+ NullLogger.Instance);
+
+ await Assert.ThrowsAsync(() =>
+ signer.SignAsync(Guid.NewGuid(), "{}", "root", TestContext.Current.CancellationToken));
+ }
+
+ private static string ComputeExpectedSignature(DevPortalOfflineManifestSigningOptions options, string manifest)
+ {
+ var payloadBytes = Encoding.UTF8.GetBytes(manifest);
+ var pae = BuildPreAuthEncoding(options.PayloadType, payloadBytes);
+
+ var secret = Convert.FromBase64String(options.Secret);
+ using var hmac = new HMACSHA256(secret);
+ var signature = hmac.ComputeHash(pae);
+ return Convert.ToBase64String(signature);
+ }
+
+ private static byte[] BuildPreAuthEncoding(string payloadType, byte[] payloadBytes)
+ {
+ var typeBytes = Encoding.UTF8.GetBytes(payloadType ?? string.Empty);
+ const string prefix = "DSSEv1";
+
+ var buffer = new byte[prefix.Length + sizeof(ulong) + sizeof(ulong) + typeBytes.Length + sizeof(ulong) + payloadBytes.Length];
+ var span = buffer.AsSpan();
+
+ var written = Encoding.UTF8.GetBytes(prefix, span);
+ span = span[written..];
+
+ BinaryPrimitives.WriteUInt64BigEndian(span, 2);
+ span = span[sizeof(ulong)..];
+
+ BinaryPrimitives.WriteUInt64BigEndian(span, (ulong)typeBytes.Length);
+ span = span[sizeof(ulong)..];
+
+ typeBytes.CopyTo(span);
+ span = span[typeBytes.Length..];
+
+ BinaryPrimitives.WriteUInt64BigEndian(span, (ulong)payloadBytes.Length);
+ span = span[sizeof(ulong)..];
+
+ payloadBytes.CopyTo(span);
+ return buffer;
+ }
+ private sealed class FixedTimeProvider : TimeProvider
+ {
+ private readonly DateTimeOffset _utcNow;
+
+ public FixedTimeProvider(DateTimeOffset utcNow)
+ {
+ _utcNow = utcNow;
+ }
+
+ public override DateTimeOffset GetUtcNow() => _utcNow;
+
+ public override long GetTimestamp() => TimeProvider.System.GetTimestamp();
+ }
+
+ private sealed class StaticOptionsMonitor : IOptionsMonitor
+ {
+ private readonly T _value;
+
+ public StaticOptionsMonitor(T value)
+ {
+ _value = value;
+ }
+
+ public T CurrentValue => _value;
+
+ public T Get(string? name) => _value;
+
+ public IDisposable OnChange(Action listener) => NullDisposable.Instance;
+
+ private sealed class NullDisposable : IDisposable
+ {
+ public static readonly NullDisposable Instance = new();
+ public void Dispose()
+ {
+ }
+ }
+ }
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/DevPortalOfflineWorkerOptions.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/DevPortalOfflineWorkerOptions.cs
new file mode 100644
index 000000000..2827ab30a
--- /dev/null
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/DevPortalOfflineWorkerOptions.cs
@@ -0,0 +1,19 @@
+using System;
+using System.Collections.Generic;
+
+namespace StellaOps.ExportCenter.Worker;
+
+public sealed class DevPortalOfflineWorkerOptions
+{
+ public bool Enabled { get; set; }
+ public Guid? BundleId { get; set; }
+ public string? StoragePrefix { get; set; }
+ public string? BundleFileName { get; set; }
+ public string? PortalDirectory { get; set; }
+ public string? SpecsDirectory { get; set; }
+ public string? ChangelogDirectory { get; set; }
+ public List? SdkSources { get; set; }
+ public Dictionary? Metadata { get; set; }
+}
+
+public sealed record DevPortalOfflineWorkerSdkSource(string Name, string Directory);
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Program.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Program.cs
index 8ecd6600c..f6d801251 100644
--- a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Program.cs
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Program.cs
@@ -1,7 +1,22 @@
-using StellaOps.ExportCenter.Worker;
-
-var builder = Host.CreateApplicationBuilder(args);
-builder.Services.AddHostedService();
-
-var host = builder.Build();
-host.Run();
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using StellaOps.ExportCenter.Core.DevPortalOffline;
+using StellaOps.ExportCenter.Infrastructure.DevPortalOffline;
+using StellaOps.ExportCenter.Worker;
+
+var builder = Host.CreateApplicationBuilder(args);
+
+builder.Services.AddSingleton(TimeProvider.System);
+
+builder.Services.Configure(builder.Configuration.GetSection("DevPortalOffline"));
+builder.Services.Configure(builder.Configuration.GetSection("DevPortalOffline:Signing"));
+builder.Services.Configure(builder.Configuration.GetSection("DevPortalOffline:Storage"));
+
+builder.Services.AddSingleton();
+builder.Services.AddSingleton();
+builder.Services.AddSingleton();
+builder.Services.AddSingleton();
+builder.Services.AddHostedService();
+
+var host = builder.Build();
+host.Run();
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Worker.cs b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Worker.cs
index 9f2e34087..1ed945f0c 100644
--- a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Worker.cs
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/Worker.cs
@@ -1,16 +1,87 @@
-namespace StellaOps.ExportCenter.Worker;
-
-public class Worker(ILogger logger) : BackgroundService
-{
- protected override async Task ExecuteAsync(CancellationToken stoppingToken)
- {
- while (!stoppingToken.IsCancellationRequested)
- {
- if (logger.IsEnabled(LogLevel.Information))
- {
- logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
- }
- await Task.Delay(1000, stoppingToken);
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using StellaOps.ExportCenter.Core.DevPortalOffline;
+
+namespace StellaOps.ExportCenter.Worker;
+
+public sealed class Worker : BackgroundService
+{
+ private readonly ILogger _logger;
+ private readonly DevPortalOfflineJob _job;
+ private readonly IOptions _options;
+
+ public Worker(
+ ILogger logger,
+ DevPortalOfflineJob job,
+ IOptions options)
+ {
+ _logger = logger ?? throw new ArgumentNullException(nameof(logger));
+ _job = job ?? throw new ArgumentNullException(nameof(job));
+ _options = options ?? throw new ArgumentNullException(nameof(options));
+ }
+
+ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
+ {
+ var options = _options.Value ?? new DevPortalOfflineWorkerOptions();
+
+ if (!options.Enabled)
+ {
+ _logger.LogInformation("DevPortal offline job disabled. Worker idling.");
+ await Task.Delay(Timeout.Infinite, stoppingToken).ConfigureAwait(false);
+ return;
+ }
+
+ try
+ {
+ var request = BuildRequest(options);
+ var outcome = await _job.ExecuteAsync(request, stoppingToken).ConfigureAwait(false);
+
+ _logger.LogInformation(
+ "DevPortal offline export completed. Bundle stored at {Key}. Manifest signature key {SignatureKey}.",
+ outcome.BundleStorage.StorageKey,
+ outcome.SignatureStorage.StorageKey);
+ }
+ catch (Exception ex) when (!stoppingToken.IsCancellationRequested)
+ {
+ _logger.LogError(ex, "DevPortal offline export job failed.");
+ throw;
+ }
+
+ await Task.Delay(Timeout.Infinite, stoppingToken).ConfigureAwait(false);
+ }
+
+ private static DevPortalOfflineJobRequest BuildRequest(DevPortalOfflineWorkerOptions options)
+ {
+ var bundleId = options.BundleId ?? Guid.NewGuid();
+ var metadata = options.Metadata is null || options.Metadata.Count == 0
+ ? null
+ : new Dictionary(options.Metadata, StringComparer.Ordinal);
+
+ var sdkSources = options.SdkSources is { Count: > 0 }
+ ? options.SdkSources
+ .Select(source => new DevPortalSdkSource(source.Name, source.Directory))
+ .ToArray()
+ : Array.Empty();
+
+ var bundleRequest = new DevPortalOfflineBundleRequest(
+ bundleId,
+ options.PortalDirectory,
+ options.SpecsDirectory,
+ sdkSources,
+ options.ChangelogDirectory,
+ metadata);
+
+ var storagePrefix = options.StoragePrefix ?? "devportal/offline";
+ var bundleFileName = string.IsNullOrWhiteSpace(options.BundleFileName)
+ ? "devportal-offline-bundle.tgz"
+ : options.BundleFileName;
+
+ return new DevPortalOfflineJobRequest(
+ bundleRequest,
+ storagePrefix,
+ bundleFileName);
+ }
+}
diff --git a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/appsettings.json b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/appsettings.json
index 690176464..695eae252 100644
--- a/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/appsettings.json
+++ b/src/ExportCenter/StellaOps.ExportCenter/StellaOps.ExportCenter.Worker/appsettings.json
@@ -1,8 +1,25 @@
-{
- "Logging": {
- "LogLevel": {
- "Default": "Information",
- "Microsoft.Hosting.Lifetime": "Information"
- }
- }
-}
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.Hosting.Lifetime": "Information"
+ }
+ },
+ "DevPortalOffline": {
+ "Enabled": false,
+ "StoragePrefix": "devportal/offline",
+ "BundleFileName": "devportal-offline-bundle.tgz",
+ "Metadata": {
+ "releaseChannel": "stable"
+ },
+ "Storage": {
+ "RootPath": "./out/devportal-offline"
+ },
+ "Signing": {
+ "KeyId": "devportal-offline-local",
+ "Secret": "ZGV2cG9ydGFsLW9mZmxpbmUtc2lnbmVyLXNlY3JldA==",
+ "Algorithm": "HMACSHA256",
+ "PayloadType": "application/vnd.stella.devportal.manifest+json"
+ }
+ }
+}
diff --git a/src/Scanner/StellaOps.Scanner.WebService/AssemblyInfo.cs b/src/Scanner/StellaOps.Scanner.WebService/AssemblyInfo.cs
index 56e7e6758..b927833e6 100644
--- a/src/Scanner/StellaOps.Scanner.WebService/AssemblyInfo.cs
+++ b/src/Scanner/StellaOps.Scanner.WebService/AssemblyInfo.cs
@@ -1,3 +1,3 @@
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("StellaOps.Scanner.WebService.Tests")]
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("StellaOps.Scanner.WebService.Tests")]
diff --git a/src/Scanner/StellaOps.Scanner.WebService/Program.cs b/src/Scanner/StellaOps.Scanner.WebService/Program.cs
index 91758c5ee..83df2c0cc 100644
--- a/src/Scanner/StellaOps.Scanner.WebService/Program.cs
+++ b/src/Scanner/StellaOps.Scanner.WebService/Program.cs
@@ -97,6 +97,8 @@ builder.Services.AddSurfaceEnvironment(options =>
builder.Services.AddSurfaceValidation();
builder.Services.AddSurfaceFileCache();
builder.Services.AddSurfaceSecrets();
+builder.Services.AddSingleton>(sp =>
+ new SurfaceCacheOptionsConfigurator(sp.GetRequiredService()));
builder.Services.AddSingleton();
builder.Services.AddSingleton();
if (bootstrapOptions.Events is { Enabled: true } eventsOptions
@@ -370,5 +372,24 @@ if (resolvedOptions.Features.EnablePolicyPreview)
apiGroup.MapReportEndpoints(resolvedOptions.Api.ReportsSegment);
apiGroup.MapRuntimeEndpoints(resolvedOptions.Api.RuntimeSegment);
-app.MapOpenApiIfAvailable();
-await app.RunAsync().ConfigureAwait(false);
+app.MapOpenApiIfAvailable();
+await app.RunAsync().ConfigureAwait(false);
+
+public partial class Program;
+
+internal sealed class SurfaceCacheOptionsConfigurator : IConfigureOptions
+{
+ private readonly ISurfaceEnvironment _surfaceEnvironment;
+
+ public SurfaceCacheOptionsConfigurator(ISurfaceEnvironment surfaceEnvironment)
+ {
+ _surfaceEnvironment = surfaceEnvironment ?? throw new ArgumentNullException(nameof(surfaceEnvironment));
+ }
+
+ public void Configure(SurfaceCacheOptions options)
+ {
+ ArgumentNullException.ThrowIfNull(options);
+ var settings = _surfaceEnvironment.Settings;
+ options.RootDirectory = settings.CacheRoot.FullName;
+ }
+}
diff --git a/src/Scanner/StellaOps.Scanner.WebService/TASKS.md b/src/Scanner/StellaOps.Scanner.WebService/TASKS.md
index c2205cfc9..f9b047f87 100644
--- a/src/Scanner/StellaOps.Scanner.WebService/TASKS.md
+++ b/src/Scanner/StellaOps.Scanner.WebService/TASKS.md
@@ -4,7 +4,8 @@
|----|--------|----------|------------|-------------|---------------|
| SCAN-REPLAY-186-001 | TODO | Scanner WebService Guild | REPLAY-CORE-185-001 | Implement scan `record` mode producing replay manifests/bundles, capture policy/feed/tool hashes, and update `docs/modules/scanner/architecture.md` referencing `docs/replay/DETERMINISTIC_REPLAY.md` Section 6. | API/worker integration tests cover record mode; docs merged; replay artifacts stored per spec. |
| SCANNER-SURFACE-02 | DONE (2025-11-05) | Scanner WebService Guild | SURFACE-FS-02 | Publish Surface.FS pointers (CAS URIs, manifests) via scan/report APIs and update attestation metadata.
2025-11-05: Surface pointers projected through scan/report endpoints, orchestrator samples + DSSE fixtures refreshed with manifest block, readiness tests updated to use validator stub. | OpenAPI updated; clients regenerated; integration tests validate pointer presence and tenancy. |
-| SCANNER-ENV-02 | DOING (2025-11-02) | Scanner WebService Guild, Ops Guild | SURFACE-ENV-02 | Wire Surface.Env helpers into WebService hosting (cache roots, feature flags) and document configuration.
2025-11-02: Cache root resolution switched to helper; feature flag bindings updated; Helm/Compose updates pending review. | Service uses helper; env table documented; helm/compose templates updated. |
+| SCANNER-ENV-02 | TODO (2025-11-06) | Scanner WebService Guild, Ops Guild | SURFACE-ENV-02 | Wire Surface.Env helpers into WebService hosting (cache roots, feature flags) and document configuration.
2025-11-02: Cache root resolution switched to helper; feature flag bindings updated; Helm/Compose updates pending review.
2025-11-05 14:55Z: Aligning readiness checks, docs, and Helm/Compose templates with Surface.Env outputs and planning test coverage for configuration fallbacks.
2025-11-06 17:05Z: Surface.Env documentation/README refreshed; warning catalogue captured for ops handoff.
2025-11-06 07:45Z: Helm values (dev/stage/prod/airgap/mirror) and Compose examples updated with `SCANNER_SURFACE_*` defaults plus rollout warning note in `deploy/README.md`.
2025-11-06 07:55Z: Paused; follow-up automation captured under `DEVOPS-OPENSSL-11-001/002` and pending Surface.Env readiness tests. | Service uses helper; env table documented; helm/compose templates updated. |
+> 2025-11-05 19:18Z: Added configurator to project wiring and unit test ensuring Surface.Env cache root is honoured.
| SCANNER-SECRETS-02 | DOING (2025-11-02) | Scanner WebService Guild, Security Guild | SURFACE-SECRETS-02 | Replace ad-hoc secret wiring with Surface.Secrets for report/export operations (registry and CAS tokens).
2025-11-02: Export/report flows now depend on Surface.Secrets stub; integration tests in progress. | Secrets fetched through shared provider; unit/integration tests cover rotation + failure cases. |
| SCANNER-EVENTS-16-301 | BLOCKED (2025-10-26) | Scanner WebService Guild | ORCH-SVC-38-101, NOTIFY-SVC-38-001 | Emit orchestrator-compatible envelopes (`scanner.event.*`) and update integration tests to verify Notifier ingestion (no Redis queue coupling). | Tests assert envelope schema + orchestrator publish; Notifier consumer harness passes; docs updated with new event contract. Blocked by .NET 10 preview OpenAPI/Auth dependency drift preventing `dotnet test` completion. |
| SCANNER-EVENTS-16-302 | DOING (2025-10-26) | Scanner WebService Guild | SCANNER-EVENTS-16-301 | Extend orchestrator event links (report/policy/attestation) once endpoints are finalised across gateway + console. | Links section covers UI/API targets; downstream consumers validated; docs/samples updated. |
diff --git a/src/Scanner/StellaOps.Scanner.Worker/AssemblyInfo.cs b/src/Scanner/StellaOps.Scanner.Worker/AssemblyInfo.cs
new file mode 100644
index 000000000..29bcd042e
--- /dev/null
+++ b/src/Scanner/StellaOps.Scanner.Worker/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("StellaOps.Scanner.Worker.Tests")]
diff --git a/src/Scanner/StellaOps.Scanner.Worker/Program.cs b/src/Scanner/StellaOps.Scanner.Worker/Program.cs
index d9d140c8a..be845f993 100644
--- a/src/Scanner/StellaOps.Scanner.Worker/Program.cs
+++ b/src/Scanner/StellaOps.Scanner.Worker/Program.cs
@@ -36,6 +36,8 @@ builder.Services.AddSurfaceEnvironment(options =>
builder.Services.AddSurfaceValidation();
builder.Services.AddSurfaceFileCache();
builder.Services.AddSurfaceSecrets();
+builder.Services.AddSingleton>(sp =>
+ new SurfaceCacheOptionsConfigurator(sp.GetRequiredService()));
builder.Services.AddSingleton();
builder.Services.AddSingleton();
builder.Services.AddSingleton();
@@ -127,3 +129,20 @@ var host = builder.Build();
await host.RunAsync();
public partial class Program;
+
+internal sealed class SurfaceCacheOptionsConfigurator : IConfigureOptions
+{
+ private readonly ISurfaceEnvironment _surfaceEnvironment;
+
+ public SurfaceCacheOptionsConfigurator(ISurfaceEnvironment surfaceEnvironment)
+ {
+ _surfaceEnvironment = surfaceEnvironment ?? throw new ArgumentNullException(nameof(surfaceEnvironment));
+ }
+
+ public void Configure(SurfaceCacheOptions options)
+ {
+ ArgumentNullException.ThrowIfNull(options);
+ var settings = _surfaceEnvironment.Settings;
+ options.RootDirectory = settings.CacheRoot.FullName;
+ }
+}
diff --git a/src/Scanner/StellaOps.Scanner.Worker/TASKS.md b/src/Scanner/StellaOps.Scanner.Worker/TASKS.md
index 6b26f1736..9c179643a 100644
--- a/src/Scanner/StellaOps.Scanner.Worker/TASKS.md
+++ b/src/Scanner/StellaOps.Scanner.Worker/TASKS.md
@@ -4,5 +4,6 @@
|----|--------|----------|------------|-------------|---------------|
| SCAN-REPLAY-186-002 | TODO | Scanner Worker Guild | REPLAY-CORE-185-001 | Enforce deterministic analyzer execution when consuming replay input bundles, emit layer Merkle metadata, and author `docs/modules/scanner/deterministic-execution.md` summarising invariants from `docs/replay/DETERMINISTIC_REPLAY.md` Section 4. | Replay mode analyzers pass determinism tests; new doc merged; integration fixtures updated. |
| SCANNER-SURFACE-01 | DOING (2025-11-02) | Scanner Worker Guild | SURFACE-FS-02 | Persist Surface.FS manifests after analyzer stages, including layer CAS metadata and EntryTrace fragments.
2025-11-02: Draft Surface.FS manifests emitted for sample scans; telemetry counters under review. | Integration tests prove cache entries exist; telemetry counters exported. |
-| SCANNER-ENV-01 | DOING (2025-11-02) | Scanner Worker Guild | SURFACE-ENV-02 | Replace ad-hoc environment reads with `StellaOps.Scanner.Surface.Env` helpers for cache roots and CAS endpoints.
2025-11-02: Worker bootstrap now resolves cache roots via helper; warning path documented; smoke tests running. | Worker boots with helper; misconfiguration warnings documented; smoke tests updated. |
+| SCANNER-ENV-01 | TODO (2025-11-06) | Scanner Worker Guild | SURFACE-ENV-02 | Replace ad-hoc environment reads with `StellaOps.Scanner.Surface.Env` helpers for cache roots and CAS endpoints.
2025-11-02: Worker bootstrap now resolves cache roots via helper; warning path documented; smoke tests running.
2025-11-05 14:55Z: Extending helper usage into cache/secrets configuration, updating worker validator wiring, and drafting docs/tests for new Surface.Env outputs.
2025-11-06 17:05Z: README/design docs updated with warning catalogue; startup logging guidance captured for ops runbooks.
2025-11-06 07:45Z: Helm/Compose env profiles (dev/stage/prod/airgap/mirror) now seed `SCANNER_SURFACE_*` defaults to keep worker cache roots aligned with Surface.Env helpers.
2025-11-06 07:55Z: Paused; pending automation tracked via `DEVOPS-OPENSSL-11-001/002` and Surface.Env test fixtures. | Worker boots with helper; misconfiguration warnings documented; smoke tests updated. |
+> 2025-11-05 19:18Z: Bound `SurfaceCacheOptions` root directory to resolved Surface.Env settings and added unit coverage around the configurator.
| SCANNER-SECRETS-01 | DOING (2025-11-02) | Scanner Worker Guild, Security Guild | SURFACE-SECRETS-02 | Adopt `StellaOps.Scanner.Surface.Secrets` for registry/CAS credentials during scan execution.
2025-11-02: Surface.Secrets provider wired for CAS token retrieval; integration tests added. | Secrets fetched via shared provider; legacy secret code removed; integration tests cover rotation. |
diff --git a/src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/SurfaceCacheOptionsConfiguratorTests.cs b/src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/SurfaceCacheOptionsConfiguratorTests.cs
new file mode 100644
index 000000000..eb7ffdf8b
--- /dev/null
+++ b/src/Scanner/__Tests/StellaOps.Scanner.WebService.Tests/SurfaceCacheOptionsConfiguratorTests.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using StellaOps.Scanner.Surface.Env;
+using StellaOps.Scanner.Surface.FS;
+using Xunit;
+
+namespace StellaOps.Scanner.WebService.Tests;
+
+public sealed class SurfaceCacheOptionsConfiguratorTests
+{
+ [Fact]
+ public void Configure_UsesSurfaceEnvironmentCacheRoot()
+ {
+ var cacheRoot = new DirectoryInfo(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")));
+ var settings = new SurfaceEnvironmentSettings(
+ new Uri("https://surface.example"),
+ "surface-cache",
+ null,
+ cacheRoot,
+ cacheQuotaMegabytes: 512,
+ prefetchEnabled: true,
+ featureFlags: Array.Empty(),
+ secrets: new SurfaceSecretsConfiguration("file", "tenant-b", "/etc/secrets", null, null, allowInline: false),
+ tenant: "tenant-b",
+ tls: new SurfaceTlsConfiguration(null, null, new X509Certificate2Collection()));
+
+ var environment = new StubSurfaceEnvironment(settings);
+ var configurator = new SurfaceCacheOptionsConfigurator(environment);
+ var options = new SurfaceCacheOptions();
+
+ configurator.Configure(options);
+
+ Assert.Equal(cacheRoot.FullName, options.RootDirectory);
+ }
+
+ private sealed class StubSurfaceEnvironment : ISurfaceEnvironment
+ {
+ public StubSurfaceEnvironment(SurfaceEnvironmentSettings settings)
+ {
+ Settings = settings;
+ }
+
+ public SurfaceEnvironmentSettings Settings { get; }
+
+ public IReadOnlyDictionary RawVariables { get; } = new Dictionary();
+ }
+}
diff --git a/src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/SurfaceCacheOptionsConfiguratorTests.cs b/src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/SurfaceCacheOptionsConfiguratorTests.cs
new file mode 100644
index 000000000..4bf957ea0
--- /dev/null
+++ b/src/Scanner/__Tests/StellaOps.Scanner.Worker.Tests/SurfaceCacheOptionsConfiguratorTests.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Security.Cryptography.X509Certificates;
+using StellaOps.Scanner.Surface.Env;
+using StellaOps.Scanner.Surface.FS;
+using Xunit;
+
+namespace StellaOps.Scanner.Worker.Tests;
+
+public sealed class SurfaceCacheOptionsConfiguratorTests
+{
+ [Fact]
+ public void Configure_UsesSurfaceEnvironmentCacheRoot()
+ {
+ var cacheRoot = new DirectoryInfo(Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString("N")));
+ var settings = new SurfaceEnvironmentSettings(
+ new Uri("https://surface.example"),
+ "surface-cache",
+ null,
+ cacheRoot,
+ cacheQuotaMegabytes: 1024,
+ prefetchEnabled: false,
+ featureFlags: Array.Empty(),
+ secrets: new SurfaceSecretsConfiguration("file", "tenant-a", "/etc/secrets", null, null, false),
+ tenant: "tenant-a",
+ tls: new SurfaceTlsConfiguration(null, null, new X509Certificate2Collection()));
+
+ var environment = new StubSurfaceEnvironment(settings);
+ var configurator = new SurfaceCacheOptionsConfigurator(environment);
+ var options = new SurfaceCacheOptions();
+
+ configurator.Configure(options);
+
+ Assert.Equal(cacheRoot.FullName, options.RootDirectory);
+ }
+
+ private sealed class StubSurfaceEnvironment : ISurfaceEnvironment
+ {
+ public StubSurfaceEnvironment(SurfaceEnvironmentSettings settings)
+ {
+ Settings = settings;
+ }
+
+ public SurfaceEnvironmentSettings Settings { get; }
+
+ public IReadOnlyDictionary RawVariables { get; } = new Dictionary();
+ }
+}
diff --git a/src/Scheduler/StellaOps.Scheduler.WebService/GraphJobs/GraphJobUpdateResult.cs b/src/Scheduler/StellaOps.Scheduler.WebService/GraphJobs/GraphJobUpdateResult.cs
index 697a7cfc1..a3715d062 100644
--- a/src/Scheduler/StellaOps.Scheduler.WebService/GraphJobs/GraphJobUpdateResult.cs
+++ b/src/Scheduler/StellaOps.Scheduler.WebService/GraphJobs/GraphJobUpdateResult.cs
@@ -1,6 +1,6 @@
namespace StellaOps.Scheduler.WebService.GraphJobs;
-internal readonly record struct GraphJobUpdateResult(bool Updated, TJob Job) where TJob : class
+public readonly record struct GraphJobUpdateResult(bool Updated, TJob Job) where TJob : class
{
public static GraphJobUpdateResult UpdatedResult(TJob job) => new(true, job);
diff --git a/src/Scheduler/StellaOps.Scheduler.WebService/PolicySimulations/PolicySimulationMetricsProvider.cs b/src/Scheduler/StellaOps.Scheduler.WebService/PolicySimulations/PolicySimulationMetricsProvider.cs
index fa3b09a7e..8d4ee9cdb 100644
--- a/src/Scheduler/StellaOps.Scheduler.WebService/PolicySimulations/PolicySimulationMetricsProvider.cs
+++ b/src/Scheduler/StellaOps.Scheduler.WebService/PolicySimulations/PolicySimulationMetricsProvider.cs
@@ -43,6 +43,7 @@ internal sealed class PolicySimulationMetricsProvider : IPolicySimulationMetrics
private readonly Histogram _latencyHistogram;
private readonly object _snapshotLock = new();
private IReadOnlyDictionary _latestQueueSnapshot = new Dictionary(StringComparer.Ordinal);
+ private string _latestTenantId = string.Empty;
private bool _disposed;
public PolicySimulationMetricsProvider(IPolicyRunJobRepository repository, TimeProvider? timeProvider = null)
@@ -83,9 +84,12 @@ internal sealed class PolicySimulationMetricsProvider : IPolicySimulationMetrics
totalQueueDepth += count;
}
+ var snapshot = new Dictionary(queueCounts, StringComparer.Ordinal);
+
lock (_snapshotLock)
{
- _latestQueueSnapshot = queueCounts;
+ _latestQueueSnapshot = snapshot;
+ _latestTenantId = tenantId;
}
var sampleSize = 200;
@@ -113,7 +117,7 @@ internal sealed class PolicySimulationMetricsProvider : IPolicySimulationMetrics
Average(durations));
return new PolicySimulationMetricsResponse(
- new PolicySimulationQueueDepth(totalQueueDepth, queueCounts),
+ new PolicySimulationQueueDepth(totalQueueDepth, snapshot),
latencyMetrics);
}
@@ -134,16 +138,21 @@ internal sealed class PolicySimulationMetricsProvider : IPolicySimulationMetrics
private IEnumerable> ObserveQueueDepth()
{
IReadOnlyDictionary snapshot;
+ string tenantId;
lock (_snapshotLock)
{
snapshot = _latestQueueSnapshot;
+ tenantId = _latestTenantId;
}
+ tenantId = string.IsNullOrWhiteSpace(tenantId) ? "unknown" : tenantId;
+
foreach (var pair in snapshot)
{
yield return new Measurement(
pair.Value,
- new KeyValuePair("status", pair.Key));
+ new KeyValuePair("status", pair.Key),
+ new KeyValuePair("tenantId", tenantId));
}
}
diff --git a/src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md b/src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md
index 235f2ca0e..a60f4d454 100644
--- a/src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md
+++ b/src/Scheduler/StellaOps.Scheduler.WebService/TASKS.md
@@ -29,12 +29,13 @@
## Policy Studio (Sprint 27)
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|----|--------|----------|------------|-------------|---------------|
-| SCHED-CONSOLE-27-001 | DONE (2025-11-03) | Scheduler WebService Guild, Policy Registry Guild | SCHED-WEB-16-103, REGISTRY-API-27-005 | Provide policy batch simulation orchestration endpoints (`/policies/simulations` POST/GET) exposing run creation, shard status, SSE progress, cancellation, and retries with RBAC enforcement. | API handles shard lifecycle with SSE heartbeats + retry headers; unauthorized requests rejected; integration tests cover submit/cancel/resume flows. |
-| SCHED-CONSOLE-27-002 | DONE (2025-11-05) | Scheduler WebService Guild, Observability Guild | SCHED-CONSOLE-27-001 | Emit telemetry endpoints/metrics (`policy_simulation_queue_depth`, `policy_simulation_latency_seconds`) and webhook callbacks for completion/failure consumed by Registry. | Metrics exposed via gateway, dashboards seeded, webhook contract documented, integration tests validate metrics emission. |
-> 2025-11-05: Resuming to align instrumentation naming with architecture spec, exercise latency recording in SSE flows, and ensure registry webhook contract (samples/docs) reflects terminal result behaviour.
-> 2025-11-05: Histogram renamed to `policy_simulation_latency_seconds`, queue gauge kept stable, new unit tests cover metrics capture/latency recording, and docs updated. Local `dotnet test` build currently blocked by existing GraphJobs visibility errors (see `StellaOps.Scheduler.WebService/GraphJobs/IGraphJobStore.cs`).
-
-## Vulnerability Explorer (Sprint 29)
+| SCHED-CONSOLE-27-001 | DONE (2025-11-03) | Scheduler WebService Guild, Policy Registry Guild | SCHED-WEB-16-103, REGISTRY-API-27-005 | Provide policy batch simulation orchestration endpoints (`/policies/simulations` POST/GET) exposing run creation, shard status, SSE progress, cancellation, and retries with RBAC enforcement. | API handles shard lifecycle with SSE heartbeats + retry headers; unauthorized requests rejected; integration tests cover submit/cancel/resume flows. |
+| SCHED-CONSOLE-27-002 | DONE (2025-11-05) | Scheduler WebService Guild, Observability Guild | SCHED-CONSOLE-27-001 | Emit telemetry endpoints/metrics (`policy_simulation_queue_depth`, `policy_simulation_latency_seconds`) and webhook callbacks for completion/failure consumed by Registry. | Metrics exposed via gateway, dashboards seeded, webhook contract documented, integration tests validate metrics emission. |
+> 2025-11-05: Resuming to align instrumentation naming with architecture spec, exercise latency recording in SSE flows, and ensure registry webhook contract (samples/docs) reflects terminal result behaviour.
+> 2025-11-05: Histogram renamed to `policy_simulation_latency_seconds`, queue gauge kept stable, new unit tests cover metrics capture/latency recording, and docs updated. Local `dotnet test` build currently blocked by existing GraphJobs visibility errors (see `StellaOps.Scheduler.WebService/GraphJobs/IGraphJobStore.cs`).
+> 2025-11-06: Added tenant-aware tagging to `policy_simulation_queue_depth` gauge samples and refreshed metrics provider snapshot coverage.
+
+## Vulnerability Explorer (Sprint 29)
| ID | Status | Owner(s) | Depends on | Description | Exit Criteria |
|----|--------|----------|------------|-------------|---------------|
| SCHED-VULN-29-001 | TODO | Scheduler WebService Guild, Findings Ledger Guild | SCHED-WEB-16-103, SBOM-VULN-29-001 | Expose resolver job APIs (`POST /vuln/resolver/jobs`, `GET /vuln/resolver/jobs/{id}`) to trigger candidate recomputation per artifact/policy change with RBAC and rate limits. | Resolver APIs documented; integration tests cover submit/status/cancel; unauthorized requests rejected. |
diff --git a/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/Fixtures/sample.bom-index.json b/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/Fixtures/sample.bom-index.json
new file mode 100644
index 000000000..8d25380fd
--- /dev/null
+++ b/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/Fixtures/sample.bom-index.json
@@ -0,0 +1,23 @@
+{
+ "schema": "scheduler-impact-index@1",
+ "generatedAt": "2025-10-01T00:00:00Z",
+ "image": {
+ "repository": "registry.stellaops.test/team/sample-service",
+ "digest": "sha256:0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef",
+ "tag": "1.0.0"
+ },
+ "components": [
+ {
+ "purl": "pkg:docker/sample-service@1.0.0",
+ "usage": [
+ "runtime"
+ ]
+ },
+ {
+ "purl": "pkg:pypi/requests@2.31.0",
+ "usage": [
+ "usedByEntrypoint"
+ ]
+ }
+ ]
+}
diff --git a/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj b/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj
index c16068b17..0dd39ae42 100644
--- a/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj
+++ b/src/Scheduler/__Libraries/StellaOps.Scheduler.ImpactIndex/StellaOps.Scheduler.ImpactIndex.csproj
@@ -8,6 +8,7 @@
+
diff --git a/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/ImpactIndexFixtureTests.cs b/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/ImpactIndexFixtureTests.cs
new file mode 100644
index 000000000..0cce2eb09
--- /dev/null
+++ b/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/ImpactIndexFixtureTests.cs
@@ -0,0 +1,52 @@
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging.Abstractions;
+using StellaOps.Scheduler.ImpactIndex;
+using StellaOps.Scheduler.Models;
+using Xunit;
+
+namespace StellaOps.Scheduler.WebService.Tests;
+
+public sealed class ImpactIndexFixtureTests
+{
+ [Fact]
+ public void FixtureDirectoryExists()
+ {
+ var fixtureDirectory = GetFixtureDirectory();
+ Assert.True(Directory.Exists(fixtureDirectory), $"Fixture directory not found: {fixtureDirectory}");
+
+ var files = Directory.EnumerateFiles(fixtureDirectory, "bom-index.json", SearchOption.AllDirectories).ToArray();
+ Assert.NotEmpty(files);
+
+ var sampleFile = Path.Combine(fixtureDirectory, "sample", "bom-index.json");
+ Assert.Contains(sampleFile, files);
+ }
+
+ [Fact]
+ public async Task FixtureImpactIndexLoadsSampleImage()
+ {
+ var fixtureDirectory = GetFixtureDirectory();
+ var options = new ImpactIndexStubOptions
+ {
+ FixtureDirectory = fixtureDirectory,
+ SnapshotId = "tests/impact-index-stub"
+ };
+
+ var index = new FixtureImpactIndex(options, TimeProvider.System, NullLogger.Instance);
+ var selector = new Selector(SelectorScope.AllImages);
+
+ var impactSet = await index.ResolveAllAsync(selector, usageOnly: false);
+
+ Assert.True(impactSet.Total > 0, "Expected the fixture impact index to load at least one image.");
+ }
+
+ private static string GetFixtureDirectory()
+ {
+ var assemblyLocation = typeof(SchedulerWebApplicationFactory).Assembly.Location;
+ var assemblyDirectory = Path.GetDirectoryName(assemblyLocation)
+ ?? AppContext.BaseDirectory;
+
+ return Path.GetFullPath(Path.Combine(assemblyDirectory, "seed-data", "impact-index"));
+ }
+}
diff --git a/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/PolicySimulationMetricsProviderTests.cs b/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/PolicySimulationMetricsProviderTests.cs
index fdde00311..c3d31c1dc 100644
--- a/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/PolicySimulationMetricsProviderTests.cs
+++ b/src/Scheduler/__Tests/StellaOps.Scheduler.WebService.Tests/PolicySimulationMetricsProviderTests.cs
@@ -1,8 +1,16 @@
+using System;
+using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics.Metrics;
+using System.Globalization;
+using System.Linq;
+using System.Threading;
+using System.Threading.Tasks;
+using MongoDB.Driver;
using StellaOps.Scheduler.Models;
using StellaOps.Scheduler.Storage.Mongo.Repositories;
using StellaOps.Scheduler.WebService.PolicySimulations;
+using Xunit;
namespace StellaOps.Scheduler.WebService.Tests;
@@ -12,14 +20,14 @@ public sealed class PolicySimulationMetricsProviderTests
public async Task CaptureAsync_ComputesQueueDepthAndLatency()
{
var now = DateTimeOffset.UtcNow;
- var queueCounts = new Dictionary
+ var counts = new Dictionary
{
[PolicyRunJobStatus.Pending] = 2,
[PolicyRunJobStatus.Dispatching] = 1,
[PolicyRunJobStatus.Submitted] = 1
};
- var jobs = new List
+ var jobs = new[]
{
CreateJob(
status: PolicyRunJobStatus.Completed,
@@ -34,8 +42,9 @@ public sealed class PolicySimulationMetricsProviderTests
cancelledAt: now.AddSeconds(-20))
};
- await using var provider = new PolicySimulationMetricsProvider(
- new StubPolicyRunJobRepository(queueCounts, jobs));
+ var repository = new StubPolicyRunJobRepository(counts, jobs);
+
+ using var provider = new PolicySimulationMetricsProvider(repository);
var response = await provider.CaptureAsync("tenant-alpha", CancellationToken.None);
@@ -49,17 +58,88 @@ public sealed class PolicySimulationMetricsProviderTests
Assert.Equal(20.0, response.Latency.P50);
Assert.Equal(28.0, response.Latency.P90);
Assert.Equal(29.0, response.Latency.P95);
- Assert.Equal(30.0, response.Latency.P99);
+ Assert.True(response.Latency.P99.HasValue);
+ Assert.Equal(29.8, response.Latency.P99.Value, 1);
+ }
+
+ [Fact]
+ public async Task CaptureAsync_UpdatesSnapshotAndEmitsTenantTaggedGauge()
+ {
+ var repository = new StubPolicyRunJobRepository();
+ repository.QueueCounts[PolicyRunJobStatus.Pending] = 3;
+ repository.QueueCounts[PolicyRunJobStatus.Dispatching] = 1;
+ repository.QueueCounts[PolicyRunJobStatus.Submitted] = 2;
+
+ var now = DateTimeOffset.Parse("2025-11-06T10:00:00Z", CultureInfo.InvariantCulture, DateTimeStyles.AdjustToUniversal);
+ repository.Jobs.Add(CreateJob(
+ status: PolicyRunJobStatus.Completed,
+ queuedAt: now.AddMinutes(-30),
+ submittedAt: now.AddMinutes(-28),
+ completedAt: now.AddMinutes(-5),
+ id: "job-1",
+ runId: "run-job-1"));
+ repository.Jobs.Add(CreateJob(
+ status: PolicyRunJobStatus.Failed,
+ queuedAt: now.AddMinutes(-20),
+ submittedAt: now.AddMinutes(-18),
+ completedAt: now.AddMinutes(-2),
+ id: "job-2",
+ runId: "run-job-2",
+ lastError: "policy engine timeout"));
+
+ using var provider = new PolicySimulationMetricsProvider(repository);
+
+ var measurements = new List<(string Status, string Tenant, long Value)>();
+ using var listener = new MeterListener
+ {
+ InstrumentPublished = (instrument, meterListener) =>
+ {
+ if (instrument.Meter.Name == "StellaOps.Scheduler.WebService.PolicySimulations" &&
+ instrument.Name == "policy_simulation_queue_depth")
+ {
+ meterListener.EnableMeasurementEvents(instrument);
+ }
+ }
+ };
+ listener.SetMeasurementEventCallback((instrument, measurement, tags, state) =>
+ {
+ var status = string.Empty;
+ var tenant = string.Empty;
+
+ foreach (var tag in tags)
+ {
+ if (string.Equals(tag.Key, "status", StringComparison.Ordinal))
+ {
+ status = tag.Value?.ToString() ?? string.Empty;
+ }
+ else if (string.Equals(tag.Key, "tenantId", StringComparison.Ordinal))
+ {
+ tenant = tag.Value?.ToString() ?? string.Empty;
+ }
+ }
+
+ measurements.Add((status, tenant, measurement));
+ });
+ listener.Start();
+
+ var response = await provider.CaptureAsync("tenant-alpha", CancellationToken.None);
+ Assert.Equal(6, response.QueueDepth.Total);
+
+ listener.RecordObservableInstruments();
+
+ Assert.Contains(measurements, item =>
+ item.Status == "pending" &&
+ item.Tenant == "tenant-alpha" &&
+ item.Value == 3);
+ listener.Dispose();
}
[Fact]
public void RecordLatency_EmitsHistogramMeasurement()
{
- var repo = new StubPolicyRunJobRepository(
- counts: new Dictionary(),
- jobs: Array.Empty());
+ var repository = new StubPolicyRunJobRepository();
- using var provider = new PolicySimulationMetricsProvider(repo);
+ using var provider = new PolicySimulationMetricsProvider(repository);
var measurements = new List();
using var listener = new MeterListener
@@ -81,64 +161,50 @@ public sealed class PolicySimulationMetricsProviderTests
measurements.Add(measurement);
}
});
-
listener.Start();
var now = DateTimeOffset.UtcNow;
- var status = new PolicyRunStatus(
- runId: "run-1",
- tenantId: "tenant-alpha",
- policyId: "policy-alpha",
- policyVersion: 1,
- mode: PolicyRunMode.Simulate,
- status: PolicyRunExecutionStatus.Succeeded,
- priority: PolicyRunPriority.Normal,
+ var latencyJob = CreateJob(
+ status: PolicyRunJobStatus.Completed,
queuedAt: now.AddSeconds(-12),
- startedAt: now.AddSeconds(-10),
- finishedAt: now,
- stats: PolicyRunStats.Empty,
- inputs: PolicyRunInputs.Empty,
- determinismHash: null,
- errorCode: null,
- error: null,
- attempts: 1,
- traceId: null,
- explainUri: null,
- metadata: ImmutableSortedDictionary.Empty,
- cancellationRequested: false,
- cancellationRequestedAt: null,
- cancellationReason: null,
- schemaVersion: null);
+ submittedAt: now.AddSeconds(-10),
+ completedAt: now,
+ id: "job-latency",
+ runId: "run-1");
+ var status = PolicyRunStatusFactory.Create(latencyJob, now);
provider.RecordLatency(status, now);
- listener.Dispose();
-
Assert.Single(measurements);
Assert.Equal(12, measurements[0], precision: 6);
+
+ listener.Dispose();
}
private static PolicyRunJob CreateJob(
PolicyRunJobStatus status,
DateTimeOffset queuedAt,
- DateTimeOffset submittedAt,
+ DateTimeOffset? submittedAt,
DateTimeOffset? completedAt,
- DateTimeOffset? cancelledAt = null)
+ DateTimeOffset? cancelledAt = null,
+ string? id = null,
+ string? runId = null,
+ string? lastError = null)
{
- var id = Guid.NewGuid().ToString("N");
- var runId = $"run:{id}";
- var updatedAt = completedAt ?? cancelledAt ?? submittedAt;
+ var jobId = id ?? Guid.NewGuid().ToString("N");
+ var resolvedRunId = runId ?? $"run:{jobId}";
+ var updatedAt = completedAt ?? cancelledAt ?? submittedAt ?? queuedAt;
return new PolicyRunJob(
SchemaVersion: SchedulerSchemaVersions.PolicyRunJob,
- Id: id,
+ Id: jobId,
TenantId: "tenant-alpha",
PolicyId: "policy-alpha",
PolicyVersion: 1,
Mode: PolicyRunMode.Simulate,
Priority: PolicyRunPriority.Normal,
PriorityRank: 0,
- RunId: runId,
+ RunId: resolvedRunId,
RequestedBy: "tester",
CorrelationId: null,
Metadata: ImmutableSortedDictionary.Empty,
@@ -146,8 +212,8 @@ public sealed class PolicySimulationMetricsProviderTests
QueuedAt: queuedAt,
Status: status,
AttemptCount: 1,
- LastAttemptAt: submittedAt,
- LastError: null,
+ LastAttemptAt: submittedAt ?? completedAt ?? queuedAt,
+ LastError: lastError,
CreatedAt: queuedAt,
UpdatedAt: updatedAt,
AvailableAt: queuedAt,
@@ -163,15 +229,32 @@ public sealed class PolicySimulationMetricsProviderTests
private sealed class StubPolicyRunJobRepository : IPolicyRunJobRepository
{
- private readonly IReadOnlyDictionary _counts;
- private readonly IReadOnlyList _jobs;
+ public StubPolicyRunJobRepository()
+ {
+ }
public StubPolicyRunJobRepository(
- IReadOnlyDictionary counts,
- IReadOnlyList jobs)
+ IDictionary counts,
+ IEnumerable jobs)
{
- _counts = counts;
- _jobs = jobs;
+ foreach (var pair in counts)
+ {
+ QueueCounts[pair.Key] = pair.Value;
+ }
+
+ Jobs.AddRange(jobs);
+ }
+
+ public Dictionary QueueCounts { get; } = new();
+ public List Jobs { get; } = new();
+
+ public Task InsertAsync(
+ PolicyRunJob job,
+ IClientSessionHandle? session = null,
+ CancellationToken cancellationToken = default)
+ {
+ Jobs.Add(job);
+ return Task.CompletedTask;
}
public Task CountAsync(
@@ -180,12 +263,17 @@ public sealed class PolicySimulationMetricsProviderTests
IReadOnlyCollection statuses,
CancellationToken cancellationToken = default)
{
+ if (statuses is null || statuses.Count == 0)
+ {
+ return Task.FromResult(QueueCounts.Values.Sum());
+ }
+
long total = 0;
foreach (var status in statuses)
{
- if (_counts.TryGetValue(status, out var value))
+ if (QueueCounts.TryGetValue(status, out var count))
{
- total += value;
+ total += count;
}
}
@@ -199,44 +287,53 @@ public sealed class PolicySimulationMetricsProviderTests
IReadOnlyCollection? statuses = null,
DateTimeOffset? queuedAfter = null,
int limit = 50,
- MongoDB.Driver.IClientSessionHandle? session = null,
+ IClientSessionHandle? session = null,
CancellationToken cancellationToken = default)
- => Task.FromResult(_jobs);
+ {
+ IEnumerable query = Jobs;
- Task IPolicyRunJobRepository.InsertAsync(
- PolicyRunJob job,
- MongoDB.Driver.IClientSessionHandle? session,
- CancellationToken cancellationToken)
- => throw new NotSupportedException();
+ if (statuses is { Count: > 0 })
+ {
+ query = query.Where(job => statuses.Contains(job.Status));
+ }
- Task IPolicyRunJobRepository.GetAsync(
+ if (queuedAfter is not null)
+ {
+ query = query.Where(job => (job.QueuedAt ?? job.CreatedAt) >= queuedAfter.Value);
+ }
+
+ var result = query.Take(limit).ToList().AsReadOnly();
+ return Task.FromResult>(result);
+ }
+
+ public Task GetAsync(
string tenantId,
string jobId,
- MongoDB.Driver.IClientSessionHandle? session,
- CancellationToken cancellationToken)
- => throw new NotSupportedException();
+ IClientSessionHandle? session = null,
+ CancellationToken cancellationToken = default)
+ => Task.FromResult(Jobs.FirstOrDefault(job => job.Id == jobId));
- Task