Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions .github/workflows/security-release-gate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,46 @@ jobs:
'versionRootRechecksEventProofOriginalOwnerSourceAndFrozenStackBeforeMetadata',
'versionRootRejectsUnknownPathsMethodsQueriesAndContradictoryRouteShapesWithSafe403',
},
'io.cattle.platform.engine.process.ProcessAuthorizationProjectUpdateTest': {
'capturedNativeProjectUpdateProofCannotBeForgedRetargetedOrGrowFields',
},
'io.cattle.platform.iaas.api.auth.projects.NativeProjectQueuedOwnerTest': {
'ordinaryNativeOwnerFullLegacyCustomAndLiveDenialsUseManagerCaptureWithoutAi',
},
'io.cattle.platform.iaas.api.auth.change.AiProjectMetadataChangeTest': {
'accountRootLockUsesTheActualAccountRowAndDetectsConcurrentMetadataChange',
'customReadKeyDoesNotBorrowGlobalOwnerWriteAuthority',
'durableAccountUpdateBindingUsesSelectedRootAndSeparateNativePrincipal',
'metadataOwnerUsesNativeProjectOwnerAndGlobalSchemaWithoutGrantingObjects',
'projectDescriptorIsMetadataOnlyAndKeepsNativeTextBounds',
'selectedAccountIdentityAndScalarSnapshotNeverCopyConfigurationOrCredentials',
'selectedProjectReadAndPreflightUseFreshGlobalNativeOwnerThenRestoreSelectedContext',
'typedProjectProcessCannotFallbackWhenDurableBindingIsMissingOrMismatched',
'unknownProjectExecutionKeepsOnlyItsOriginalDurableProcessWithoutReplayOrTerminalAuthority',
},
'io.cattle.platform.iaas.api.auditing.AiServiceUpgradeAuditTest': {
'bindingReasonDetailSurvivesJsonOutboxReplayAndCanonicalProjectionAsClientEvidence',
'privateProjectCaptureKeepsSelectedAuditScopeForPrimaryAndQueueOutcomes',
},
'io.cattle.platform.iaas.api.auth.ai.AiToolCallEventServiceTest': {
'bindingDetailCapabilityKeepsLegacyConstructorAndDurableReadonlyAcksCompatible',
'invalidReasonDetailsNeverReachDurableSink',
},
'io.cattle.platform.iaas.api.auth.ai.view.AiProjectCollectionOwnerTest': {
'adminNativeFullAndLegacySeeNonMembershipProjectsWithoutWideningMemberOrReadonly',
'allIsPrivateToTypedProjectCollectionAndNeverChangesSingleGetOrOtherTypesOrAcceptsModelAll',
'exactProjectCustomDenyAndReadonlyKeysRetainExactSetsThroughNativeCommonCollectionFilter',
},
'io.cattle.platform.iaas.api.auth.change.AiLoadBalancerMetadataChangeTest': {
'onlyLoadBalancerMetadataFieldsAndIntentAreAdmitted',
'freshNativeStackAndKeyChecksProtectTheSparsePutAndPrivateParentRead',
'scalarSnapshotsAndStackContextCasExcludeConfigurationAndRejectScopeOrMovement',
'loadBalancerPlanKeepsHumanApprovalSnapshotCasRevocationAndOneClaim',
'loadBalancerMetadataLocksActualServiceRowAndDetectsNativeScalarChanges',
'queuedNativeServiceUpdateUsesExactLbKindUuidStackAndCapturedProcess',
'queuedNativeOwnerRetainsFullLegacySchemaRevisionAndRevocationChecks',
'ordinaryNativeV1V2FullAndLegacyCaptureNeverEnterTheAiMandatoryBranch',
},
}
suites = []
observed = {}
Expand Down
13 changes: 13 additions & 0 deletions COMPATIBILITY.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,18 @@
# Compatibility Contract

## Engine 0.183.372 candidate — not published

Engine 0.183.372 candidate; not published or runtime qualified.

Selected Project name/description updates use the native Project queued owner, fresh role/schema/Key limits, normal human approval, revision/CAS and the original durable claim. Visible nonselected Projects remain queryable but require normal context selection and a fresh reference before editing. Ordinary Full, legacy and custom native Project updates share the native owner; no generic HTTP tool or membership/network/auth change is added.

Typed Project discovery uses the native all=true option and the common per-row Key collection filter. The optional fixed client-reported binding detail uses the existing audit start ACK capability; canonical evidence remains client_reported with NOT_EVALUATED/REPORTED, never a backend authorization denial. Six fixed role-field metadata entries permit only that optional input and read-only capability. HTTP tuple and native route/action grants remain unchanged.

Load-balancer metadata adds only name and description through the existing native Service owner, fresh target/Stack reads, Key ceilings, human approval and one durable process claim. Ports, lbConfig, certificates, scaling, lifecycle and children are unchanged; the eight new source controls are not native acceptance.

All 173 prior required identities are preserved and 26 new exact methods are registered (199 total). Source composition checks are separate from normal full App/Spring/schema/security CI, original artifact qualification and native business acceptance, which remain pending. Existing security findings remain disclosed; workflow SLSA is not supplied. Matching Web/Bridge and Server integration are separate; no whole-243 completion is claimed.


## Engine 0.183.371 published

Typed Host metadata visibility and receipt checks use the native Host model;
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ RUN set -eux; \
printf 'Acquire::Retries "5";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\nAcquire::http::Pipeline-Depth "0";\nAcquire::https::CaInfo "/etc/ssl/certs/ca-certificates.crt";\nAcquire::https::Verify-Peer "true";\nAcquire::https::Verify-Host "true";\nAcquire::AllowInsecureRepositories "false";\nAPT::Get::AllowUnauthenticated "false";\n' > /etc/apt/apt.conf.d/80pasturestack-retries; \
printf 'Types: deb\nURIs: https://snapshot.ubuntu.com/ubuntu/%s\nSuites: resolute-security\nComponents: main\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' \
"${UBUNTU_APT_SECURITY_SNAPSHOT}" > /etc/apt/sources.list.d/pasturestack-security.sources; \
apt-get update; \
apt-get update --error-on=any; \
set --; \
for package in libexpat1 libsqlite3-0 libssh2-1t64; do \
test "$(grep -c "^${package}=" /licenses/ubuntu-security-packages.lock)" -eq 1; \
Expand All @@ -100,7 +100,7 @@ RUN set -eux; \
test "$(dpkg-query -W -f='${Version}' "${package}")" = "${UBUNTU_APT_OPENSSL_VERSION}"; \
done; \
rm -f /etc/apt/sources.list.d/pasturestack-security.sources; \
apt-get update; \
apt-get update --error-on=any; \
set --; \
for package in libpython3.14-minimal libpython3.14-stdlib python3.14-minimal python3.14 python3.14-venv curl libcurl3t64-gnutls libcurl4t64 ca-certificates libbrotli1 libpcre2-8-0 libpcre2-posix3; do \
architecture=amd64; \
Expand Down Expand Up @@ -144,7 +144,7 @@ RUN set -eux; \
xz-utils="${UBUNTU_APT_XZ_UTILS_VERSION}"; \
printf 'Types: deb\nURIs: https://snapshot.ubuntu.com/ubuntu/%s\nSuites: resolute-security\nComponents: main\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' \
"${UBUNTU_APT_SECURITY_SNAPSHOT}" > /etc/apt/sources.list.d/pasturestack-security.sources; \
apt-get update; \
apt-get update --error-on=any; \
for package in libssl3t64 openssl openssl-provider-legacy; do \
test "$(dpkg-query -W -f='${Version}' "${package}")" = "${UBUNTU_APT_OPENSSL_VERSION}"; \
done; \
Expand Down
6 changes: 3 additions & 3 deletions Dockerfile.dapper
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ RUN set -eux; \
printf 'Acquire::Retries "5";\nAcquire::http::Timeout "30";\nAcquire::https::Timeout "30";\nAcquire::http::Pipeline-Depth "0";\nAcquire::https::CaInfo "/etc/ssl/certs/ca-certificates.crt";\nAcquire::https::Verify-Peer "true";\nAcquire::https::Verify-Host "true";\nAcquire::AllowInsecureRepositories "false";\nAPT::Get::AllowUnauthenticated "false";\n' > /etc/apt/apt.conf.d/80pasturestack-retries; \
printf 'Types: deb\nURIs: https://snapshot.ubuntu.com/ubuntu/%s\nSuites: resolute-security\nComponents: main\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' \
"${UBUNTU_APT_SECURITY_SNAPSHOT}" > /etc/apt/sources.list.d/pasturestack-security.sources; \
apt-get update; \
apt-get update --error-on=any; \
set --; \
for package in libexpat1 libsqlite3-0 libssh2-1t64; do \
test "$(grep -c "^${package}=" /licenses/ubuntu-security-packages.lock)" -eq 1; \
Expand All @@ -117,7 +117,7 @@ RUN set -eux; \
test "$(dpkg-query -W -f='${Version}' "${package}")" = "${UBUNTU_APT_OPENSSL_VERSION}"; \
done; \
rm -f /etc/apt/sources.list.d/pasturestack-security.sources; \
apt-get update; \
apt-get update --error-on=any; \
set --; \
for package in libpython3.14-minimal libpython3.14-stdlib python3.14-minimal python3.14 python3.14-venv curl libcurl3t64-gnutls libcurl4t64 ca-certificates libbrotli1 libpcre2-8-0 libpcre2-posix3; do \
architecture=amd64; \
Expand Down Expand Up @@ -161,7 +161,7 @@ RUN set -eux; \
xz-utils="${UBUNTU_APT_XZ_UTILS_VERSION}"; \
printf 'Types: deb\nURIs: https://snapshot.ubuntu.com/ubuntu/%s\nSuites: resolute-security\nComponents: main\nSigned-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg\nSnapshot: no\n' \
"${UBUNTU_APT_SECURITY_SNAPSHOT}" > /etc/apt/sources.list.d/pasturestack-security.sources; \
apt-get update; \
apt-get update --error-on=any; \
for package in libssl3t64 openssl openssl-provider-legacy; do \
test "$(dpkg-query -W -f='${Version}' "${package}")" = "${UBUNTU_APT_OPENSSL_VERSION}"; \
done; \
Expand Down
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ Rancher 1.6 ecosystem. It is not affiliated with Rancher Labs or SUSE.
This fork of [`rancher/cattle`](https://github.com/rancher/cattle) preserves
upstream history, authorship, licenses, and dependency notices.

## Next candidate: Engine 0.183.372

Selected-Project and load-balancer name/description metadata, native queued-owner authorization and fixed client-reported audit detail are in [source and CI preparation](docs/releases/orchestration-engine-0.183.372.md). Publication and native acceptance are pending; use the published release below.

## Latest published release: Engine 0.183.371

[Engine 0.183.371](https://github.com/PastureStack/orchestration-engine/releases/tag/v0.183.371)
Expand Down Expand Up @@ -177,7 +181,7 @@ Before publishing an Engine artifact, run the complete package gate:

```sh
bash scripts/check-cattle-jdk25-full-package
ENGINE_VERSION=0.183.371 bash scripts/build --release
ENGINE_VERSION=0.183.372 bash scripts/build --release
bash scripts/check-release-artifact dist/artifacts/cattle.jar
```

Expand Down
2 changes: 1 addition & 1 deletion code/framework/api-pub-sub-jetty/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.cattle</groupId>
<artifactId>cattle-parent</artifactId>
<version>0.183.371</version>
<version>0.183.372</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>
<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion code/framework/api-pub-sub/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.cattle</groupId>
<artifactId>cattle-parent</artifactId>
<version>0.183.371</version>
<version>0.183.372</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>
<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion code/framework/api/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<artifactId>cattle-parent</artifactId>
<groupId>io.cattle</groupId>
<version>0.183.371</version>
<version>0.183.372</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@

/** Bounded client evidence, never proof of authorization or business completion. */
public record ClientToolAuditEvent(String requestId, String command, String phase,
String status, String reason, String correlationId) {
String status, String reason, String correlationId, String reasonDetail) {
public static final String BRIDGE_PROJECT_BINDING_REQUIRED = "BRIDGE_PROJECT_BINDING_REQUIRED";
public ClientToolAuditEvent(String requestId, String command, String phase,
String status, String reason, String correlationId) {
this(requestId, command, phase, status, reason, correlationId, null);
}
public static final Set<String> COMMANDS = Set.of("find_stacks", "find_services", "get_service",
"preview_service_upgrade", "apply_service_upgrade", "get_operation", "update_service_description",
"list_capabilities", "find_resources", "get_resource", "preview_resource_change", "apply_resource_change", "unknown");
Expand All @@ -19,6 +24,9 @@ public static boolean validId(String value) {
public boolean valid() {
return validId(requestId) && command != null && COMMANDS.contains(command)
&& status != null && STATUSES.contains(status) && reason != null && REASONS.contains(reason)
&& (reasonDetail == null || BRIDGE_PROJECT_BINDING_REQUIRED.equals(reasonDetail)
&& "preview_resource_change".equals(command) && "result".equals(phase)
&& "needs_user".equals(status) && "NEEDS_USER".equals(reason))
&& (("start".equals(phase) && "pending".equals(status) && correlationId == null)
|| ("result".equals(phase) && !"pending".equals(status) && validId(correlationId)));
}
Expand Down
2 changes: 1 addition & 1 deletion code/framework/archaius/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.cattle</groupId>
<artifactId>cattle-meta-parent</artifactId>
<version>0.183.371</version>
<version>0.183.372</version>
<relativePath>../../meta-parent/pom.xml</relativePath>
</parent>
</project>
2 changes: 1 addition & 1 deletion code/framework/async/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<groupId>io.cattle</groupId>
<artifactId>cattle-parent</artifactId>
<version>0.183.371</version>
<version>0.183.372</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>
<dependencies>
Expand Down
2 changes: 1 addition & 1 deletion code/framework/auditing/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<parent>
<artifactId>cattle-parent</artifactId>
<groupId>io.cattle</groupId>
<version>0.183.371</version>
<version>0.183.372</version>
<relativePath>../../parent/pom.xml</relativePath>
</parent>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public class AuditServiceImpl implements AuditService, ApiKeyAuditSink, ApiReque
public static final Set<String> API_KEY_AUDIT_FIELDS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
"eventId", "keyId", "decision", "outcome", "httpStatus", "responseCode", "requestId", "actor",
"targetType", "targetId", "operation", "policyRevision", "reason", "phase", "preview", "processId", "processName", "hostUuid", "failureCode",
"clientReportedCommand", "clientReportedPhase", "clientReportedStatus", "clientReportedReason",
"clientReportedCommand", "clientReportedPhase", "clientReportedStatus", "clientReportedReason", "clientReportedReasonDetail",
"clientCorrelationId", "evidenceSource", "channel")));
private static final Set<String> SENSITIVE_AUDIT_FIELDS = Set.of(
"secretvalue", "secretvalues", "password", "newsecret", "oldsecret", "adminaccountpassword", "serviceaccountpassword",
Expand Down Expand Up @@ -374,7 +374,8 @@ private void recordServiceDecision(ApiRequest request, Policy policy, String act
@Override
public void recordResourceChangeDecision(ApiRequest request, Policy policy, String action, String receiptId,
String resourceType, Long resourceId, boolean allowed, String reason) {
if (!Set.of("stack", "service", "container", "externalService", "dnsService", "certificate", "host", "aiResourceChangePlan")
if (!Set.of("stack", "service", "container", "externalService", "dnsService", "certificate", "host", "project",
"loadBalancerService", "aiResourceChangePlan")
.contains(resourceType))
throw new IllegalArgumentException("Invalid resource-change audit target");
recordTypedResourceDecision(request, policy, action, receiptId, "aichange", resourceType, resourceId,
Expand Down Expand Up @@ -434,6 +435,7 @@ public void recordClientToolEvent(ApiRequest request, Policy policy, ClientToolA
data.put("evidenceSource", "client_reported"); data.put("channel", "webmcp-client-report");
data.put("clientReportedCommand", report.command()); data.put("clientReportedPhase", report.phase());
data.put("clientReportedStatus", report.status()); data.put("clientReportedReason", report.reason());
if (report.reasonDetail() != null) data.put("clientReportedReasonDetail", report.reasonDetail());
if (report.correlationId() != null) data.put("clientCorrelationId", report.correlationId());
Map<String, Object> event = new HashMap<>();
event.put("resourceType", "aiToolCallEvent"); event.put("resourceId", null);
Expand Down
Loading
Loading