mirror of
https://github.com/fosrl/pangolin.git
synced 2026-02-18 02:46:37 +00:00
Compare commits
3 Commits
crowdin_de
...
1.15.4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
843b13ed57 | ||
|
|
be89e5ca55 | ||
|
|
333625f199 |
39
.github/workflows/cicd.yml
vendored
39
.github/workflows/cicd.yml
vendored
@@ -525,41 +525,10 @@ jobs:
|
|||||||
VERIFIED_INDEX_KEYLESS=false
|
VERIFIED_INDEX_KEYLESS=false
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If index verification fails, attempt to verify child platform manifests
|
# Check if verification succeeded
|
||||||
if [ "${VERIFIED_INDEX}" != "true" ] || [ "${VERIFIED_INDEX_KEYLESS}" != "true" ]; then
|
if [ "${VERIFIED_INDEX}" != "true" ] && [ "${VERIFIED_INDEX_KEYLESS}" != "true" ]; then
|
||||||
echo "Index verification not available; attempting child manifest verification for ${BASE_IMAGE}:${IMAGE_TAG}"
|
echo "⚠️ WARNING: Verification not available for ${BASE_IMAGE}:${IMAGE_TAG}"
|
||||||
CHILD_VERIFIED=false
|
echo "This may be due to registry propagation delays. Continuing anyway."
|
||||||
|
|
||||||
for ARCH in arm64 amd64; do
|
|
||||||
CHILD_TAG="${IMAGE_TAG}-${ARCH}"
|
|
||||||
echo "Resolving child digest for ${BASE_IMAGE}:${CHILD_TAG}"
|
|
||||||
CHILD_DIGEST="$(skopeo inspect --retry-times 3 docker://${BASE_IMAGE}:${CHILD_TAG} | jq -r '.Digest' || true)"
|
|
||||||
if [ -n "${CHILD_DIGEST}" ] && [ "${CHILD_DIGEST}" != "null" ]; then
|
|
||||||
CHILD_REF="${BASE_IMAGE}@${CHILD_DIGEST}"
|
|
||||||
echo "==> cosign verify (public key) child ${CHILD_REF}"
|
|
||||||
if retry_verify "cosign verify --key env://COSIGN_PUBLIC_KEY '${CHILD_REF}' -o text"; then
|
|
||||||
CHILD_VERIFIED=true
|
|
||||||
echo "Public key verification succeeded for child ${CHILD_REF}"
|
|
||||||
else
|
|
||||||
echo "Public key verification failed for child ${CHILD_REF}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "==> cosign verify (keyless policy) child ${CHILD_REF}"
|
|
||||||
if retry_verify "cosign verify --certificate-oidc-issuer '${issuer}' --certificate-identity-regexp '${id_regex}' '${CHILD_REF}' -o text"; then
|
|
||||||
CHILD_VERIFIED=true
|
|
||||||
echo "Keyless verification succeeded for child ${CHILD_REF}"
|
|
||||||
else
|
|
||||||
echo "Keyless verification failed for child ${CHILD_REF}"
|
|
||||||
fi
|
|
||||||
else
|
|
||||||
echo "No child digest found for ${BASE_IMAGE}:${CHILD_TAG}; skipping"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "${CHILD_VERIFIED}" != "true" ]; then
|
|
||||||
echo "Failed to verify index and no child manifests verified for ${BASE_IMAGE}:${IMAGE_TAG}"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
fi
|
fi
|
||||||
) || TAG_FAILED=true
|
) || TAG_FAILED=true
|
||||||
|
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ export const sandboxLimitSet: LimitSet = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const freeLimitSet: LimitSet = {
|
export const freeLimitSet: LimitSet = {
|
||||||
[FeatureId.USERS]: { value: 5, description: "Starter limit" },
|
[FeatureId.SITES]: { value: 5, description: "Basic limit" },
|
||||||
[FeatureId.SITES]: { value: 5, description: "Starter limit" },
|
[FeatureId.USERS]: { value: 5, description: "Basic limit" },
|
||||||
[FeatureId.DOMAINS]: { value: 5, description: "Starter limit" },
|
[FeatureId.DOMAINS]: { value: 5, description: "Basic limit" },
|
||||||
[FeatureId.REMOTE_EXIT_NODES]: { value: 1, description: "Starter limit" },
|
[FeatureId.REMOTE_EXIT_NODES]: { value: 1, description: "Basic limit" },
|
||||||
};
|
};
|
||||||
|
|
||||||
export const tier1LimitSet: LimitSet = {
|
export const tier1LimitSet: LimitSet = {
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import { CreateOrgIdpResponse } from "@server/routers/orgIdp/types";
|
|||||||
import { isSubscribed } from "#private/lib/isSubscribed";
|
import { isSubscribed } from "#private/lib/isSubscribed";
|
||||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
import privateConfig from "#private/lib/config";
|
import privateConfig from "#private/lib/config";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
|
||||||
const paramsSchema = z.strictObject({ orgId: z.string().nonempty() });
|
const paramsSchema = z.strictObject({ orgId: z.string().nonempty() });
|
||||||
|
|
||||||
@@ -122,12 +123,14 @@ export async function createOrgOidcIdp(
|
|||||||
|
|
||||||
let { autoProvision } = parsedBody.data;
|
let { autoProvision } = parsedBody.data;
|
||||||
|
|
||||||
const subscribed = await isSubscribed(
|
if (build == "saas") { // this is not paywalled with a ee license because this whole endpoint is restricted
|
||||||
orgId,
|
const subscribed = await isSubscribed(
|
||||||
tierMatrix.deviceApprovals
|
orgId,
|
||||||
);
|
tierMatrix.deviceApprovals
|
||||||
if (!subscribed) {
|
);
|
||||||
autoProvision = false;
|
if (!subscribed) {
|
||||||
|
autoProvision = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const key = config.getRawConfig().server.secret!;
|
const key = config.getRawConfig().server.secret!;
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import config from "@server/lib/config";
|
|||||||
import { isSubscribed } from "#private/lib/isSubscribed";
|
import { isSubscribed } from "#private/lib/isSubscribed";
|
||||||
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
import { tierMatrix } from "@server/lib/billing/tierMatrix";
|
||||||
import privateConfig from "#private/lib/config";
|
import privateConfig from "#private/lib/config";
|
||||||
|
import { build } from "@server/build";
|
||||||
|
|
||||||
const paramsSchema = z
|
const paramsSchema = z
|
||||||
.object({
|
.object({
|
||||||
@@ -127,12 +128,15 @@ export async function updateOrgOidcIdp(
|
|||||||
|
|
||||||
let { autoProvision } = parsedBody.data;
|
let { autoProvision } = parsedBody.data;
|
||||||
|
|
||||||
const subscribed = await isSubscribed(
|
if (build == "saas") {
|
||||||
orgId,
|
// this is not paywalled with a ee license because this whole endpoint is restricted
|
||||||
tierMatrix.deviceApprovals
|
const subscribed = await isSubscribed(
|
||||||
);
|
orgId,
|
||||||
if (!subscribed) {
|
tierMatrix.deviceApprovals
|
||||||
autoProvision = false;
|
);
|
||||||
|
if (!subscribed) {
|
||||||
|
autoProvision = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if IDP exists and is of type OIDC
|
// Check if IDP exists and is of type OIDC
|
||||||
|
|||||||
@@ -797,7 +797,7 @@ async function notAllowed(
|
|||||||
) {
|
) {
|
||||||
let loginPage: LoginPage | null = null;
|
let loginPage: LoginPage | null = null;
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
const subscribed = await isSubscribed(
|
const subscribed = await isSubscribed( // this is fine because the org login page is only a saas feature
|
||||||
orgId,
|
orgId,
|
||||||
tierMatrix.loginPageDomain
|
tierMatrix.loginPageDomain
|
||||||
);
|
);
|
||||||
@@ -854,7 +854,7 @@ async function headerAuthChallenged(
|
|||||||
) {
|
) {
|
||||||
let loginPage: LoginPage | null = null;
|
let loginPage: LoginPage | null = null;
|
||||||
if (orgId) {
|
if (orgId) {
|
||||||
const subscribed = await isSubscribed(orgId, tierMatrix.loginPageDomain);
|
const subscribed = await isSubscribed(orgId, tierMatrix.loginPageDomain); // this is fine because the org login page is only a saas feature
|
||||||
if (subscribed) {
|
if (subscribed) {
|
||||||
loginPage = await getOrgLoginPage(orgId);
|
loginPage = await getOrgLoginPage(orgId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ import {
|
|||||||
import { FeatureId } from "@server/lib/billing/features";
|
import { FeatureId } from "@server/lib/billing/features";
|
||||||
|
|
||||||
// Plan tier definitions matching the mockup
|
// Plan tier definitions matching the mockup
|
||||||
type PlanId = "starter" | "home" | "team" | "business" | "enterprise";
|
type PlanId = "basic" | "home" | "team" | "business" | "enterprise";
|
||||||
|
|
||||||
type PlanOption = {
|
type PlanOption = {
|
||||||
id: PlanId;
|
id: PlanId;
|
||||||
@@ -73,8 +73,8 @@ type PlanOption = {
|
|||||||
|
|
||||||
const planOptions: PlanOption[] = [
|
const planOptions: PlanOption[] = [
|
||||||
{
|
{
|
||||||
id: "starter",
|
id: "basic",
|
||||||
name: "Starter",
|
name: "Basic",
|
||||||
price: "Free",
|
price: "Free",
|
||||||
tierType: null
|
tierType: null
|
||||||
},
|
},
|
||||||
@@ -109,10 +109,10 @@ const planOptions: PlanOption[] = [
|
|||||||
|
|
||||||
// Tier limits mapping derived from limit sets
|
// Tier limits mapping derived from limit sets
|
||||||
const tierLimits: Record<
|
const tierLimits: Record<
|
||||||
Tier | "starter",
|
Tier | "basic",
|
||||||
{ users: number; sites: number; domains: number; remoteNodes: number }
|
{ users: number; sites: number; domains: number; remoteNodes: number }
|
||||||
> = {
|
> = {
|
||||||
starter: {
|
basic: {
|
||||||
users: freeLimitSet[FeatureId.USERS]?.value ?? 0,
|
users: freeLimitSet[FeatureId.USERS]?.value ?? 0,
|
||||||
sites: freeLimitSet[FeatureId.SITES]?.value ?? 0,
|
sites: freeLimitSet[FeatureId.SITES]?.value ?? 0,
|
||||||
domains: freeLimitSet[FeatureId.DOMAINS]?.value ?? 0,
|
domains: freeLimitSet[FeatureId.DOMAINS]?.value ?? 0,
|
||||||
@@ -183,7 +183,7 @@ export default function BillingPage() {
|
|||||||
// Confirmation dialog state
|
// Confirmation dialog state
|
||||||
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
const [showConfirmDialog, setShowConfirmDialog] = useState(false);
|
||||||
const [pendingTier, setPendingTier] = useState<{
|
const [pendingTier, setPendingTier] = useState<{
|
||||||
tier: Tier | "starter";
|
tier: Tier | "basic";
|
||||||
action: "upgrade" | "downgrade";
|
action: "upgrade" | "downgrade";
|
||||||
planName: string;
|
planName: string;
|
||||||
price: string;
|
price: string;
|
||||||
@@ -402,8 +402,8 @@ export default function BillingPage() {
|
|||||||
pendingTier.action === "upgrade" ||
|
pendingTier.action === "upgrade" ||
|
||||||
pendingTier.action === "downgrade"
|
pendingTier.action === "downgrade"
|
||||||
) {
|
) {
|
||||||
// If downgrading to starter (free tier), go to Stripe portal
|
// If downgrading to basic (free tier), go to Stripe portal
|
||||||
if (pendingTier.tier === "starter") {
|
if (pendingTier.tier === "basic") {
|
||||||
handleModifySubscription();
|
handleModifySubscription();
|
||||||
} else if (hasSubscription) {
|
} else if (hasSubscription) {
|
||||||
handleChangeTier(pendingTier.tier);
|
handleChangeTier(pendingTier.tier);
|
||||||
@@ -417,7 +417,7 @@ export default function BillingPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const showTierConfirmation = (
|
const showTierConfirmation = (
|
||||||
tier: Tier | "starter",
|
tier: Tier | "basic",
|
||||||
action: "upgrade" | "downgrade",
|
action: "upgrade" | "downgrade",
|
||||||
planName: string,
|
planName: string,
|
||||||
price: string
|
price: string
|
||||||
@@ -432,9 +432,9 @@ export default function BillingPage() {
|
|||||||
|
|
||||||
// Get current plan ID from tier
|
// Get current plan ID from tier
|
||||||
const getCurrentPlanId = (): PlanId => {
|
const getCurrentPlanId = (): PlanId => {
|
||||||
if (!hasSubscription || !currentTier) return "starter";
|
if (!hasSubscription || !currentTier) return "basic";
|
||||||
const plan = planOptions.find((p) => p.tierType === currentTier);
|
const plan = planOptions.find((p) => p.tierType === currentTier);
|
||||||
return plan?.id || "starter";
|
return plan?.id || "basic";
|
||||||
};
|
};
|
||||||
|
|
||||||
const currentPlanId = getCurrentPlanId();
|
const currentPlanId = getCurrentPlanId();
|
||||||
@@ -451,8 +451,8 @@ export default function BillingPage() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (plan.id === currentPlanId) {
|
if (plan.id === currentPlanId) {
|
||||||
// If it's the starter plan (starter with no subscription), show as current but disabled
|
// If it's the basic plan (basic with no subscription), show as current but disabled
|
||||||
if (plan.id === "starter" && !hasSubscription) {
|
if (plan.id === "basic" && !hasSubscription) {
|
||||||
return {
|
return {
|
||||||
label: "Current Plan",
|
label: "Current Plan",
|
||||||
action: () => {},
|
action: () => {},
|
||||||
@@ -484,10 +484,10 @@ export default function BillingPage() {
|
|||||||
plan.name,
|
plan.name,
|
||||||
plan.price + (" " + plan.priceDetail || "")
|
plan.price + (" " + plan.priceDetail || "")
|
||||||
);
|
);
|
||||||
} else if (plan.id === "starter") {
|
} else if (plan.id === "basic") {
|
||||||
// Show confirmation for downgrading to starter (free tier)
|
// Show confirmation for downgrading to basic (free tier)
|
||||||
showTierConfirmation(
|
showTierConfirmation(
|
||||||
"starter",
|
"basic",
|
||||||
"downgrade",
|
"downgrade",
|
||||||
plan.name,
|
plan.name,
|
||||||
plan.price
|
plan.price
|
||||||
@@ -566,7 +566,7 @@ export default function BillingPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Check if downgrading to a tier would violate current usage limits
|
// Check if downgrading to a tier would violate current usage limits
|
||||||
const checkLimitViolations = (targetTier: Tier | "starter"): Array<{
|
const checkLimitViolations = (targetTier: Tier | "basic"): Array<{
|
||||||
feature: string;
|
feature: string;
|
||||||
currentUsage: number;
|
currentUsage: number;
|
||||||
newLimit: number;
|
newLimit: number;
|
||||||
|
|||||||
Reference in New Issue
Block a user