ci: use shared ci-workflows Maven workflow #61
No files matched your search
@@ -0,0 +1,7 @@
|
||||
name: build
|
||||
on:
|
||||
push:
|
||||
jobs:
|
||||
maven:
|
||||
uses: self:KofTwentyTwo/ci-workflows/.gitea/workflows/maven.yaml@main
|
||||
secrets: inherit
|
||||
@@ -1,25 +0,0 @@
|
||||
# Standard QRun release caller (v2, thin contract): every push and manual dispatch delegates to the protected qrun-release-v1 channel. Do not edit per repository.
|
||||
name: qrun-release
|
||||
on:
|
||||
push: {}
|
||||
workflow_dispatch: {}
|
||||
permissions:
|
||||
contents: read
|
||||
actions: read
|
||||
jobs:
|
||||
release:
|
||||
uses: self:KofTwentyTwo/platform-ci/.gitea/workflows/java-docker.yaml@qrun-release-v1
|
||||
with:
|
||||
runner: linux-small
|
||||
docker-runner: container-build
|
||||
browsers: true
|
||||
browser-runner: browser-build
|
||||
postpublish:
|
||||
if: ${{ needs.release.outputs.capture == 'true' }}
|
||||
needs: release
|
||||
permissions:
|
||||
contents: write
|
||||
actions: write
|
||||
uses: self:KofTwentyTwo/platform-ci/.gitea/workflows/qrun-source-version.yaml@qrun-release-v1
|
||||
with:
|
||||
runner: linux-small
|
||||
@@ -1,72 +0,0 @@
|
||||
name: Release candidate
|
||||
'on':
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
dry_run:
|
||||
description: Plan a cut without changing release state
|
||||
type: boolean
|
||||
default: false
|
||||
finalize:
|
||||
description: Retry finalization of an existing cut; do not cut another RC
|
||||
type: boolean
|
||||
default: false
|
||||
recover:
|
||||
description: Recover the same published RC after a deployment timeout; never
|
||||
reupload
|
||||
type: boolean
|
||||
default: false
|
||||
circle_build:
|
||||
description: Original release run id (recovery only)
|
||||
type: string
|
||||
default: ''
|
||||
merge_sha:
|
||||
description: Existing cut merge_sha (finalize retry only)
|
||||
type: string
|
||||
default: ''
|
||||
bump_sha:
|
||||
description: Existing cut bump_sha (finalize retry only)
|
||||
type: string
|
||||
default: ''
|
||||
branch:
|
||||
description: Existing cut branch (finalize retry only)
|
||||
type: string
|
||||
default: ''
|
||||
version:
|
||||
description: Existing cut version (finalize retry only)
|
||||
type: string
|
||||
default: ''
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
branches:
|
||||
- develop
|
||||
permissions:
|
||||
contents: read
|
||||
jobs:
|
||||
release-rc:
|
||||
# The old qbit-rc-published repository_dispatch is replaced by the already-proven workflow_dispatch
|
||||
# completion: the publisher's own ActionsWRITE job dispatches this workflow with finalize=true plus
|
||||
# merge_sha/bump_sha/branch/version (same inputs as the manual finalize retry).
|
||||
permissions:
|
||||
contents: write
|
||||
actions: read
|
||||
pull-requests: write
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
|| (github.event_name == 'pull_request' && github.event.pull_request.merged
|
||||
== true && github.event.pull_request.base.ref == 'develop' && contains(github.event.pull_request.labels.*.name,
|
||||
'release:rc'))
|
||||
uses: self:KofTwentyTwo/platform-ci/.gitea/workflows/qbit-release-rc.yaml@qrun-release-v1
|
||||
with:
|
||||
dry_run: ${{ github.event_name == 'workflow_dispatch' && inputs.dry_run || false
|
||||
}}
|
||||
finalize: ${{ github.event_name == 'workflow_dispatch' && inputs.finalize }}
|
||||
recover: ${{ github.event_name == 'workflow_dispatch' && inputs.recover || false
|
||||
}}
|
||||
circle_build: ${{ github.event_name == 'workflow_dispatch' && inputs.circle_build
|
||||
|| '' }}
|
||||
merge_sha: ${{ inputs.merge_sha || '' }}
|
||||
bump_sha: ${{ inputs.bump_sha || '' }}
|
||||
branch: ${{ inputs.branch || '' }}
|
||||
version: ${{ inputs.version || '' }}
|
||||
secrets:
|
||||
QRUN_TAG_SIGNING_KEY: ${{ secrets.QRUN_TAG_SIGNING_KEY }}
|
||||
@@ -161,7 +161,7 @@ public class SchemaDriftTest
|
||||
{
|
||||
return (surfacePath);
|
||||
}
|
||||
String regex = surfacePath.replace("{key}", "\\{[^/]+\\}");
|
||||
String regex = java.util.regex.Pattern.quote(surfacePath).replace("{key}", "\\E\\{[^/]+\\}\\Q");
|
||||
Iterator<Map.Entry<String, JsonNode>> fields = paths.fields();
|
||||
while(fields.hasNext())
|
||||
{
|
||||
|
||||
@@ -255,9 +255,36 @@ public final class AuthentikTestStack
|
||||
TestApi admin = admin();
|
||||
try
|
||||
{
|
||||
long[] nextRetry = { System.currentTimeMillis() + 60_000 };
|
||||
waitFor(Duration.ofMinutes(8), "all three kof22 blueprints applied", () ->
|
||||
isSuccessful(admin, INFRA_BLUEPRINT) && isSuccessful(admin, BOOTSTRAP_BLUEPRINT) && isSuccessful(admin, TOKEN_BLUEPRINT)
|
||||
{
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// built-in blueprints may race our custom dependencies on first //
|
||||
// boot, leaving one of ours in "error" or never applied //
|
||||
// ("unknown"); re-apply it (throttled). //
|
||||
////////////////////////////////////////////////////////////////////
|
||||
if(System.currentTimeMillis() >= nextRetry[0])
|
||||
{
|
||||
nextRetry[0] = System.currentTimeMillis() + 30_000;
|
||||
for(String name : List.of(INFRA_BLUEPRINT, BOOTSTRAP_BLUEPRINT, TOKEN_BLUEPRINT))
|
||||
{
|
||||
try
|
||||
{
|
||||
JSONObject current = blueprint(name);
|
||||
if(current != null && List.of("error", "unknown").contains(current.optString("status")))
|
||||
{
|
||||
admin.post("/managed/blueprints/" + current.getString("pk") + "/apply/", new JSONObject());
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
// Bootstrap authentication and built-in dependencies settle after HTTP readiness.
|
||||
}
|
||||
}
|
||||
}
|
||||
return (isSuccessful(admin, INFRA_BLUEPRINT) && isSuccessful(admin, BOOTSTRAP_BLUEPRINT) && isSuccessful(admin, TOKEN_BLUEPRINT)
|
||||
&& admin.first("/core/users/?username=" + SERVICE_ACCOUNT) != null);
|
||||
});
|
||||
}
|
||||
catch(IllegalStateException e)
|
||||
{
|
||||
@@ -278,8 +305,16 @@ public final class AuthentikTestStack
|
||||
}
|
||||
try
|
||||
{
|
||||
worker.getLogs().lines().filter(line -> line.contains("blueprint") && (line.contains("error") || line.contains("warning") || line.contains("fail")))
|
||||
worker.getLogs().lines().filter(line -> (line.contains("blueprint") && (line.contains("error") || line.contains("warning") || line.contains("fail")))
|
||||
|| line.contains("\"level\": \"error\"") || line.contains("Traceback"))
|
||||
.filter(line -> !line.contains("clear_failed_blueprints"))
|
||||
.limit(60).forEach(line -> System.err.println("worker: " + line));
|
||||
////////////////////////////////////////////////////////////////
|
||||
// blueprints re-applied through the API run in the server //
|
||||
////////////////////////////////////////////////////////////////
|
||||
server.getLogs().lines().filter(line -> line.contains("\"level\": \"error\"") || line.contains("\"level\": \"warning\"") || line.contains("Traceback"))
|
||||
.filter(line -> !line.contains("Base URL is not configured"))
|
||||
.limit(60).forEach(line -> System.err.println("server: " + line));
|
||||
}
|
||||
catch(RuntimeException unavailable)
|
||||
{
|
||||
|
||||
+2
-2
@@ -174,7 +174,7 @@ class InvitationEnrollmentContractIT
|
||||
}
|
||||
assertThat(used).isNotNull();
|
||||
assertThat(used.getJSONObject("user").optInt("pk", -1)).isNotEqualTo(userPk);
|
||||
var config = assignment == null ? new com.kingsrook.qbits.authentik.AuthentikQBitConfig().withBaseUrl(stack.baseUrl())
|
||||
var config = assignment == null ? new com.kingsrook.qbits.authentik.AuthentikQBitConfig().withBaseUrl(stack.baseUrl()).withAllowInsecureHttp(true)
|
||||
.withApiToken(stack.serviceAccountToken()).withAppKey("kof22-admin").withListCacheTtlSeconds(0) : assignment.config;
|
||||
var instance = assignment == null ? com.kingsrook.qbits.authentik.AuthentikTestSupport.produce(config) : assignment.instance;
|
||||
com.kingsrook.qqq.backend.core.context.QContext.init(instance,
|
||||
@@ -265,7 +265,7 @@ class InvitationEnrollmentContractIT
|
||||
String actor = create(admin, "/core/users/", new JSONObject().put("username", owner + "-operator").put("name", "Invitation operator")
|
||||
.put("email", owner + "-operator@example.test").put("type", "internal").put("path", "users/invitation-contract"), cleanup);
|
||||
assertThat(admin.post("/core/groups/" + admins + "/add_user/", new JSONObject().put("pk", Integer.parseInt(actor))).status()).isEqualTo(204);
|
||||
config = new AuthentikQBitConfig().withBaseUrl(stack.baseUrl()).withApiToken(stack.serviceAccountToken()).withAppKey("kof22-admin")
|
||||
config = new AuthentikQBitConfig().withBaseUrl(stack.baseUrl()).withAllowInsecureHttp(true).withApiToken(stack.serviceAccountToken()).withAppKey("kof22-admin")
|
||||
.withListCacheTtlSeconds(0).withGroupCacheTtlSeconds(0).withInvitationFlow(owner).withLocalBackendName("memory")
|
||||
.withRecoveryEmailStage("kof22-recovery-email")
|
||||
.withFeatures(EnumSet.of(AuthentikFeature.READ, AuthentikFeature.USERS, AuthentikFeature.GROUPS, AuthentikFeature.MEMBERSHIP));
|
||||
|
||||
@@ -96,7 +96,7 @@ class Phase1ReadContractIT
|
||||
void beforeEach() throws QException
|
||||
{
|
||||
config = new AuthentikQBitConfig()
|
||||
.withBaseUrl(stack.baseUrl())
|
||||
.withBaseUrl(stack.baseUrl()).withAllowInsecureHttp(true)
|
||||
.withApiToken(stack.serviceAccountToken())
|
||||
.withAppKey("kof22-admin")
|
||||
.withApplicationsInScope(List.of(AuthentikTestStack.APP_SLUG))
|
||||
|
||||
@@ -126,7 +126,7 @@ class QbitReadContractIT
|
||||
void beforeEach() throws QException
|
||||
{
|
||||
config = new AuthentikQBitConfig()
|
||||
.withBaseUrl(stack.baseUrl())
|
||||
.withBaseUrl(stack.baseUrl()).withAllowInsecureHttp(true)
|
||||
.withApiToken(stack.serviceAccountToken())
|
||||
.withAppKey("kof22-admin")
|
||||
.withListCacheTtlSeconds(0);
|
||||
|
||||
@@ -155,7 +155,7 @@ class QbitWriteContractIT
|
||||
{
|
||||
MemoryRecordStore.getInstance().reset();
|
||||
config = new AuthentikQBitConfig()
|
||||
.withBaseUrl(stack.baseUrl())
|
||||
.withBaseUrl(stack.baseUrl()).withAllowInsecureHttp(true)
|
||||
.withApiToken(stack.serviceAccountToken())
|
||||
.withAppKey("kof22-admin")
|
||||
.withListCacheTtlSeconds(0)
|
||||
|
||||
@@ -89,7 +89,7 @@ class SchemaDriftIT
|
||||
for(java.util.Iterator<String> it = paths.fieldNames(); it.hasNext(); )
|
||||
{
|
||||
String candidate = it.next();
|
||||
if(candidate.equals(path) || candidate.matches(path.replace("{key}", "\\{[^/]+\\}")))
|
||||
if(candidate.equals(path) || candidate.matches(java.util.regex.Pattern.quote(path).replace("{key}", "\\E\\{[^/]+\\}\\Q")))
|
||||
{
|
||||
return (SchemaDriftTest.parameterNames(schema, paths.get(candidate).get(operation.method())));
|
||||
}
|
||||
|
||||
@@ -579,7 +579,7 @@ class TokenContractIT
|
||||
private void configureQbit(int owner, String subject) throws Exception
|
||||
{
|
||||
MemoryRecordStore.getInstance().reset();
|
||||
config = new AuthentikQBitConfig().withBaseUrl(stack.baseUrl()).withApiToken(stack.serviceAccountToken()).withAppKey("kof22-admin")
|
||||
config = new AuthentikQBitConfig().withBaseUrl(stack.baseUrl()).withAllowInsecureHttp(true).withApiToken(stack.serviceAccountToken()).withAppKey("kof22-admin")
|
||||
.withListCacheTtlSeconds(0).withGroupCacheTtlSeconds(0).withBulkPacingMillis(0).withLocalBackendName("memory")
|
||||
.withRecoveryEmailStage("kof22-recovery-email")
|
||||
.withFeatures(EnumSet.of(AuthentikFeature.READ, AuthentikFeature.USERS, AuthentikFeature.TOKENS))
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.kingsrook.qbits.authentik.sync;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.sql.DataSource;
|
||||
import com.kingsrook.qbits.authentik.RequiresDockerCondition;
|
||||
@@ -27,6 +28,7 @@ import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.postgresql.ds.PGSimpleDataSource;
|
||||
import org.testcontainers.DockerClientFactory;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import com.github.dockerjava.api.model.ExposedPort;
|
||||
import com.github.dockerjava.api.model.PortBinding;
|
||||
@@ -39,6 +41,7 @@ import com.github.dockerjava.api.model.Ports;
|
||||
@ExtendWith(RequiresDockerCondition.class)
|
||||
class AuthentikMirrorPostgresIT extends AuthentikMirrorSqlTest
|
||||
{
|
||||
private static final Set<String> LOCAL_DOCKER_HOSTS = Set.of("localhost", "127.0.0.1");
|
||||
private static PostgreSQLContainer<?> postgres;
|
||||
private String schema;
|
||||
|
||||
@@ -55,7 +58,11 @@ class AuthentikMirrorPostgresIT extends AuthentikMirrorSqlTest
|
||||
.withCreateContainerCmdModifier(command ->
|
||||
{
|
||||
command.withName(owner);
|
||||
command.getHostConfig().withPortBindings(new PortBinding(Ports.Binding.bindIp("127.0.0.1"), new ExposedPort(5432)));
|
||||
// Loopback-only only when the daemon is local; a remote daemon (CI) is reached via its host address.
|
||||
if(LOCAL_DOCKER_HOSTS.contains(DockerClientFactory.instance().dockerHostIpAddress()))
|
||||
{
|
||||
command.getHostConfig().withPortBindings(new PortBinding(Ports.Binding.bindIp("127.0.0.1"), new ExposedPort(5432)));
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
|
||||
+8
-1
@@ -17,6 +17,7 @@
|
||||
package com.kingsrook.qbits.authentik.sync;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import javax.sql.DataSource;
|
||||
import com.kingsrook.qbits.authentik.RequiresDockerCondition;
|
||||
@@ -24,6 +25,7 @@ import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.postgresql.ds.PGSimpleDataSource;
|
||||
import org.testcontainers.DockerClientFactory;
|
||||
import org.testcontainers.containers.PostgreSQLContainer;
|
||||
import com.github.dockerjava.api.model.ExposedPort;
|
||||
import com.github.dockerjava.api.model.PortBinding;
|
||||
@@ -36,6 +38,7 @@ import com.github.dockerjava.api.model.Ports;
|
||||
@ExtendWith(RequiresDockerCondition.class)
|
||||
class AuthentikWebhookInboxPostgresIT extends AuthentikWebhookInboxTest
|
||||
{
|
||||
private static final Set<String> LOCAL_DOCKER_HOSTS = Set.of("localhost", "127.0.0.1");
|
||||
private static PostgreSQLContainer<?> postgres;
|
||||
private String schema;
|
||||
|
||||
@@ -53,7 +56,11 @@ class AuthentikWebhookInboxPostgresIT extends AuthentikWebhookInboxTest
|
||||
.withCreateContainerCmdModifier(command ->
|
||||
{
|
||||
command.withName(owner);
|
||||
command.getHostConfig().withPortBindings(new PortBinding(Ports.Binding.bindIp("127.0.0.1"), new ExposedPort(5432)));
|
||||
// Loopback-only only when the daemon is local; a remote daemon (CI) is reached via its host address.
|
||||
if(LOCAL_DOCKER_HOSTS.contains(DockerClientFactory.instance().dockerHostIpAddress()))
|
||||
{
|
||||
command.getHostConfig().withPortBindings(new PortBinding(Ports.Binding.bindIp("127.0.0.1"), new ExposedPort(5432)));
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
|
||||
Reference in new issue
Block a user