Skip to content

activate licenses before verification#12570

Open
isabelizimm wants to merge 2 commits intomainfrom
activate-verify
Open

activate licenses before verification#12570
isabelizimm wants to merge 2 commits intomainfrom
activate-verify

Conversation

@isabelizimm
Copy link
Contributor

@isabelizimm isabelizimm commented Mar 17, 2026

Currently, we are only verifying if licenses are available and not expired. This has been working since the licenses come with evaluation periods, so they can be used without activation so long as that eval period has not expired. However, what we actually want is to activate the license file, if possible, and not use the eval period.

Release Notes

New Features

  • N/A

Bug Fixes

QA Notes

In logs when Positron Server is starting up, you should see a "days left" log that is reflective of days left in the license, not the evaluation period (which is 45 days).

@github-actions
Copy link

github-actions bot commented Mar 17, 2026

E2E Tests 🚀
This PR will run tests tagged with: @:critical

readme  valid tags

@isabelizimm isabelizimm marked this pull request as ready for review March 18, 2026 15:34
@isabelizimm isabelizimm requested a review from Copilot March 18, 2026 17:54
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates Positron Server’s RSA license-file handling to prefer activating licenses via license-manager (instead of relying on evaluation periods) so startup “days left” reflects the actual license term.

Changes:

  • Switch RSA license-file path from validateWithManager to activateWithManager during server startup license handling.
  • Implement an activation flow in licenseManager.ts (initialize if needed → activate-file → interpret status/days-left).
  • Add license-manager.conf assets under Linux activation resources (x86_64 + aarch64).

Reviewed changes

Copilot reviewed 2 out of 8 changed files in this pull request and generated 4 comments.

File Description
src/vs/server/node/remoteLicenseKey.ts Routes RSA license files through activation flow instead of verification-only.
src/vs/server/node/licenseManager.ts Adds JSON-command helpers + activation/verification logic and exports activateWithManager.
resources/activation/linux/x86_64/license-manager.conf Adds a license-manager companion config/blob for x86_64.
resources/activation/linux/aarch64/license-manager.conf Adds a license-manager companion config/blob for aarch64.

Comment on lines 137 to +159
/**
* Validates a license file.
*
* @param connectionToken The connection token.
* @param licenseFile The path to the license file.
* @returns The license validation result.
*/
export async function validateLicenseFile(connectionToken: string, licenseFile: string): Promise<ILicenseValidationResult> {
if (!fs.existsSync(licenseFile)) {
console.error('License file does not exist: ', licenseFile);
return { valid: false };
}
// Read the contents of the license file into a string.
try {
const contents = fs.readFileSync(licenseFile, 'utf8');
// Check if this looks like a JSON file (trimmed content starts with '{')
const trimmedContents = contents.trim();
if (trimmedContents.startsWith('{')) {
return validateLicense(connectionToken, contents);
} else if (trimmedContents.startsWith('-----BEGIN RSTUDIO LICENSE-----')) {
// This is an RSA license file, let the license manager handle it.
const installPath = path.join(FileAccess.asFileUri('').fsPath, '..');
return await validateWithManager(installPath, licenseFile);
return await activateWithManager(installPath, licenseFile);
Comment on lines +25 to +29
/**
* Grace period in days after license expiration.
*/
const GRACE_PERIOD_DAYS = 30;

Comment on lines +162 to +177
const status = result.status?.toLowerCase() || '';
const daysLeft = result['days-left'] ?? 0;

// Only accept active or evaluation licenses
if (status !== 'active' && status !== 'evaluation') {
throw new Error(`Invalid license status: ${output.status}`);
// Handle expired licenses
if (status === 'expired') {
// Check grace period
if (daysLeft < -GRACE_PERIOD_DAYS) {
throw new Error('License has expired beyond the grace period. Please renew your license.');
}
console.warn(`License expired but within ${GRACE_PERIOD_DAYS}-day grace period.`);
} else if (status !== 'activated' && status !== 'evaluation') {
throw new Error(`Invalid license status: ${status}`);
}

// License is valid
const daysLeftMsg = daysLeft !== undefined ? `Days left: ${daysLeft}` : 'Days left: unknown';
console.log(`Successfully validated Positron license (Status: ${output.status}, ${daysLeftMsg})`);
const daysLeftMsg = daysLeft !== undefined ? `Days left: ${daysLeft}` : '';
console.log(`Successfully activated Positron license (Status: ${status}${daysLeftMsg ? ', ' + daysLeftMsg : ''})`);
Comment on lines +188 to +194
async verifyLicenseFile(licenseFilePath: string): Promise<ILicenseValidationResult> {
if (!fs.existsSync(licenseFilePath)) {
throw new Error(`License file not found: ${licenseFilePath}`);
}

const result = await this.statusOffline();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants