Register the external_probe Pro entitlement

Add external_probe to the licensing feature enumeration, Pro tier
membership, self-hosted feature catalog, feature map, upgrade matrix
and pricing handoff, with the entitlement contract goldens updated.
The capability is served by the community binary - the entitlement
alone gates it, like relay. No existing free functionality changes:
local availability checks stay ungated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
courtmanr@gmail.com
2026-07-27 10:12:35 +01:00
parent ca3e4b5709
commit fc5aaef391
12 changed files with 47 additions and 4 deletions
@@ -81,6 +81,7 @@ describe('pricingHandoff', () => {
'audit_logging',
'advanced_reporting',
'agent_profiles',
'external_probe',
]);
for (const key of paidCatalogFeatureKeys) {
expect(getUpgradeFallbackDestination(key)).toBe(
@@ -201,6 +201,7 @@ describe('selfHostedPlans', () => {
'audit_logging',
'advanced_reporting',
'agent_profiles',
'external_probe',
]);
expect(
SELF_HOSTED_PLAN_DEFINITIONS.map((plan) => ({
@@ -67,6 +67,7 @@ const IN_PRODUCT_PRICING_DESTINATIONS: Record<string, string> = {
audit_logging: SELF_HOSTED_PRO_BILLING_PLAN_HREF,
advanced_reporting: SELF_HOSTED_PRO_BILLING_PLAN_HREF,
agent_profiles: SELF_HOSTED_PRO_BILLING_PLAN_HREF,
external_probe: SELF_HOSTED_PRO_BILLING_PLAN_HREF,
long_term_metrics: SELF_HOSTED_PRO_BILLING_PLAN_HREF,
};
@@ -261,6 +261,23 @@ export const SELF_HOSTED_FEATURE_CATALOG: readonly GeneratedSelfHostedFeatureCat
pro: true,
},
},
{
key: 'external_probe',
displayName: 'External Probes',
comparisonName: 'External Probes',
showInComparisonTable: true,
displayableInSelfHostedPlan: true,
roles: {
community: 'hidden',
relay: 'hidden',
pro: 'included_extra',
},
includedIn: {
community: false,
relay: false,
pro: true,
},
},
{
key: 'kubernetes_ai',
displayName: 'Kubernetes AI Analysis (Compatibility)',
+4 -4
View File
@@ -7639,7 +7639,7 @@ func TestContract_EntitlementPayloadMonitoredSystemUsageJSONSnapshot(t *testing.
}
const want = `{
"capabilities":["update_alerts","sso","advanced_sso","ai_patrol","relay","mobile_app","push_notifications","long_term_metrics","ai_alerts","ai_autofix","kubernetes_ai","agent_profiles","rbac","audit_logging","advanced_reporting"],
"capabilities":["update_alerts","sso","advanced_sso","ai_patrol","relay","mobile_app","push_notifications","long_term_metrics","ai_alerts","ai_autofix","kubernetes_ai","agent_profiles","rbac","audit_logging","advanced_reporting","external_probe"],
"limits":[],
"subscription_state":"active",
"upgrade_reasons":[],
@@ -7694,7 +7694,7 @@ func TestContract_SelfHostedCommunityEntitlementsJSONSnapshot(t *testing.T) {
{"key":"ai_alerts","reason":"Upgrade to Pro so Patrol can investigate issues instead of handing you a stack of symptoms.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=ai_alerts"},
{"key":"rbac","reason":"Upgrade to Pro when more than one operator needs safe access boundaries around infrastructure changes.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=rbac"},
{"key":"agent_profiles","reason":"Upgrade to Pro to standardize agent behavior across systems without reconfiguring every install by hand.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=agent_profiles"},
{"key":"audit_logging","reason":"Upgrade to Pro to keep a trustworthy action trail for incident review, accountability, and compliance.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=audit_logging"},
{"key":"external_probe","reason":"Upgrade to Pro to run availability checks from a probe outside the monitored site, with independent alerting.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=external_probe"},{"key":"audit_logging","reason":"Upgrade to Pro to keep a trustworthy action trail for incident review, accountability, and compliance.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=audit_logging"},
{"key":"advanced_reporting","reason":"Upgrade to Pro to turn live infrastructure state into shareable reports without manual screenshot work.","action_url":"https://pulserelay.pro/pricing?utm_source=pulse\u0026utm_medium=app\u0026utm_campaign=upgrade\u0026feature=advanced_reporting"}
],
"tier":"free",
@@ -7780,7 +7780,7 @@ func TestContract_EntitlementPayloadMonitoredSystemUsageUnavailableJSONSnapshot(
}
const want = `{
"capabilities":["update_alerts","sso","advanced_sso","ai_patrol","relay","mobile_app","push_notifications","long_term_metrics","ai_alerts","ai_autofix","kubernetes_ai","agent_profiles","rbac","audit_logging","advanced_reporting"],
"capabilities":["update_alerts","sso","advanced_sso","ai_patrol","relay","mobile_app","push_notifications","long_term_metrics","ai_alerts","ai_autofix","kubernetes_ai","agent_profiles","rbac","audit_logging","advanced_reporting","external_probe"],
"limits":[],
"subscription_state":"active",
"upgrade_reasons":[],
@@ -7822,7 +7822,7 @@ func TestContract_EntitlementPayloadLifetimeJSONSnapshot(t *testing.T) {
}
const want = `{
"capabilities":["update_alerts","sso","advanced_sso","ai_patrol","relay","mobile_app","push_notifications","long_term_metrics","ai_alerts","ai_autofix","kubernetes_ai","agent_profiles","rbac","audit_logging","advanced_reporting"],
"capabilities":["update_alerts","sso","advanced_sso","ai_patrol","relay","mobile_app","push_notifications","long_term_metrics","ai_alerts","ai_autofix","kubernetes_ai","agent_profiles","rbac","audit_logging","advanced_reporting","external_probe"],
"limits":[],
"subscription_state":"active",
"upgrade_reasons":[],
+1
View File
@@ -58,6 +58,7 @@ const (
featureAuditLoggingValue = pkglicensing.FeatureAuditLogging
featureRBACValue = pkglicensing.FeatureRBAC
featureAdvancedReportingValue = pkglicensing.FeatureAdvancedReporting
featureExternalProbeValue = pkglicensing.FeatureExternalProbe
featureWhiteLabelValue = pkglicensing.FeatureWhiteLabel
featureLongTermMetricsValue = pkglicensing.FeatureLongTermMetrics
featureDemoFixturesValue = pkglicensing.FeatureDemoFixtures
+1
View File
@@ -17,6 +17,7 @@ const (
FeatureSSO = licensing.FeatureSSO
FeatureAdvancedSSO = licensing.FeatureAdvancedSSO
FeatureAdvancedReporting = licensing.FeatureAdvancedReporting
FeatureExternalProbe = licensing.FeatureExternalProbe
FeatureLongTermMetrics = licensing.FeatureLongTermMetrics
FeatureRelay = licensing.FeatureRelay
FeatureMobileApp = licensing.FeatureMobileApp
+1
View File
@@ -17,6 +17,7 @@ var DefaultFeatureKeys = []string{
FeatureRBAC,
FeatureAuditLogging,
FeatureAdvancedReporting,
FeatureExternalProbe,
FeatureMultiTenant,
}
+2
View File
@@ -33,6 +33,7 @@ const (
FeatureRBAC = "rbac" // Role-Based Access Control
FeatureAuditLogging = "audit_logging" // Persistent audit logs with signing
FeatureAdvancedReporting = "advanced_reporting" // PDF/CSV reporting engine
FeatureExternalProbe = "external_probe" // Availability checks run from outside the monitored site
// MSP/Enterprise tier features
FeatureMultiUser = "multi_user" // Multi-user (likely merged with RBAC)
@@ -249,6 +250,7 @@ var proFeatures = appendFeatures(relayFeatures,
FeatureRBAC,
FeatureAuditLogging,
FeatureAdvancedReporting,
FeatureExternalProbe,
)
// mspFeatures adds multi-tenant policy on top of pro.
@@ -44,6 +44,7 @@ var orderedFeatureMetadataKeys = []string{
FeatureAuditLogging,
FeatureAdvancedReporting,
FeatureAgentProfiles,
FeatureExternalProbe,
FeatureKubernetesAI,
FeatureMultiUser,
FeatureWhiteLabel,
@@ -253,6 +254,20 @@ var featureMetadataCatalog = map[string]FeatureMetadata{
UpgradeReason: "Upgrade to Pro to turn live infrastructure state into shareable reports without manual screenshot work.",
UpgradePriority: 9,
},
FeatureExternalProbe: {
Key: FeatureExternalProbe,
DisplayName: "External Probes",
ComparisonName: "External Probes",
ShowInComparisonTable: true,
DisplayableInPlanUI: true,
SelfHostedRoles: SelfHostedFeatureRoles{
Community: SelfHostedFeatureRoleHidden,
Relay: SelfHostedFeatureRoleHidden,
Pro: SelfHostedFeatureRoleIncludedExtra,
},
UpgradeReason: "Upgrade to Pro to run availability checks from a probe outside the monitored site, with independent alerting.",
UpgradePriority: 7,
},
FeatureMultiUser: {
Key: FeatureMultiUser,
DisplayName: "Multi-User Mode",
+2
View File
@@ -93,6 +93,8 @@ func UpgradeURLForFeature(feature string) string {
return DefaultUpgradeURL + "&feature=audit_logging"
case FeatureAdvancedReporting:
return DefaultUpgradeURL + "&feature=advanced_reporting"
case FeatureExternalProbe:
return DefaultUpgradeURL + "&feature=external_probe"
default:
return DefaultUpgradeURL
}
+1
View File
@@ -147,6 +147,7 @@ func TestUpgradeReasonMatrixDerivesFromCanonicalFeatureMetadata(t *testing.T) {
FeatureAIAlerts,
FeatureRBAC,
FeatureAgentProfiles,
FeatureExternalProbe,
FeatureAuditLogging,
FeatureAdvancedReporting,
}