Skip to content

Commit

Permalink
Validate Chromium inputs for OT creation (UI) (GoogleChrome#3790)
Browse files Browse the repository at this point in the history
* Add chromium file checks for OT creation

* reorganize functions

* change critical trial logic
  • Loading branch information
DanielRyanSmith authored Apr 11, 2024
1 parent 459345c commit ac2413b
Show file tree
Hide file tree
Showing 4 changed files with 163 additions and 8 deletions.
150 changes: 149 additions & 1 deletion client-src/elements/chromedash-ot-creation-page.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ import {ORIGIN_TRIAL_CREATION_FIELDS} from './form-definition.js';
import {SHARED_STYLES} from '../css/shared-css.js';
import {FORM_STYLES} from '../css/forms-css.js';
import {ALL_FIELDS} from './form-field-specs.js';
import json5 from 'json5';


const WEBFEATURE_FILE_URL = 'https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom?format=TEXT';
const ENABLED_FEATURES_FILE_URL = 'https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/renderer/platform/runtime_enabled_features.json5?format=TEXT';
const GRACE_PERIOD_FILE = 'https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/common/origin_trials/manual_completion_origin_trial_features.cc?format=TEXT';


export class ChromedashOTCreationPage extends LitElement {
Expand All @@ -32,6 +38,11 @@ export class ChromedashOTCreationPage extends LitElement {
appTitle: {type: String},
fieldValues: {type: Array},
showApprovalsFields: {type: Boolean},

// Chromium file contents for validating inputs.
webfeatureFile: {type: String},
enabledFeaturesJson: {type: Object},
gracePeriodFile: {type: String},
};
}

Expand All @@ -44,6 +55,9 @@ export class ChromedashOTCreationPage extends LitElement {
this.appTitle = '';
this.fieldValues = [];
this.showApprovalsFields = false;
this.webfeatureFile = '';
this.enabledFeaturesJson = undefined;
this.gracePeriodFile = '';
}

connectedCallback() {
Expand Down Expand Up @@ -178,7 +192,132 @@ export class ChromedashOTCreationPage extends LitElement {
setupScrollToHash(this);
}

handleFormSubmit(e) {
async getChromiumFile(url) {
const resp = await fetch(url);
const respJson = await resp.text();
return atob(respJson);
}

// Check that the code has landed that is used to monitor feature usage.
async checkWebfeatureUseCounter(field) {
if (!this.webfeatureFile) {
this.webfeatureFile = await this.getChromiumFile(WEBFEATURE_FILE_URL);
}
const webfeatureCounterExists = this.webfeatureFile.includes(`${field.value} =`);
if (!webfeatureCounterExists) {
field.checkMessage = html`
<span class="check-error">
<b>Error</b>: UseCounter name not found in file.
</span>`;
return true;
} else {
field.checkMessage = nothing;
}
return false;
}

// Check that code has landed that is required for the origin trial feature.
async checkChromiumTrialName(field) {
if (!this.enabledFeaturesJson) {
const enabledFeaturesFileText = await this.getChromiumFile(ENABLED_FEATURES_FILE_URL);
this.enabledFeaturesJson = json5.parse(enabledFeaturesFileText);
}
if (!this.enabledFeaturesJson.data.some(
feature => feature.origin_trial_feature_name === field.value)) {
field.checkMessage = html`
<span class="check-error">
<b>Error</b>: Name not found in file.
</span>`;
return true;
} else {
field.checkMessage = nothing;
}
return false;
}

// Check that code has landed that is required for third party support.
async checkThirdPartySupport(field) {
if (!field.value) {
field.checkMessage = nothing;
return false;
}
const chromiumTrialName = this.fieldValues.find(
field => field.name === 'ot_chromium_trial_name').value;
if (!this.enabledFeaturesJson) {
const enabledFeaturesFileText = await this.getChromiumFile(ENABLED_FEATURES_FILE_URL);
this.enabledFeaturesJson = json5.parse(enabledFeaturesFileText);
}

const thirdPartySupportEnabled = this.enabledFeaturesJson.data.every(
feature => {
return (feature.origin_trial_feature_name !== chromiumTrialName ||
feature.origin_trial_allows_third_party);
});
if (!thirdPartySupportEnabled) {
field.checkMessage = html`
<br>
<span class="check-error">
<b>Error</b>: Property not set in file.
</span>`;
return true;
} else {
field.checkMessage = nothing;
}
return false;
}

// Check that code has landed that is required for critical trials.
async checkCriticalTrial(field) {
if (!field.value) {
field.checkMessage = nothing;
return false;
}
const chromiumTrialName = this.fieldValues.find(
field => field.name === 'ot_chromium_trial_name').value;
if (!this.gracePeriodFile) {
this.gracePeriodFile = await this.getChromiumFile(GRACE_PERIOD_FILE);
}
const includedInGracePeriodArray = this.gracePeriodFile.includes(
`blink::mojom::OriginTrialFeature::k${chromiumTrialName}`);
if (!includedInGracePeriodArray) {
field.checkMessage = html`
<br>
<span class="check-error">
<b>Error</b>: Trial name not found in file.
</span>`;
return true;
} else {
field.checkMessage = nothing;
}
return false;
}

/**
* Check that given args related to Chromium are valid.
* @returns Whether any inputs cannot be found in Chromium files.
*/
async handleChromiumChecks() {
// Clear saved file info in order to fetch the most recent version.
this.webfeatureFile = '';
this.enabledFeaturesJson = undefined;
this.gracePeriodFile = '';
let hasErrors = false;

for (const field of this.fieldValues) {
if (field.name === 'ot_webfeature_use_counter') {
hasErrors = hasErrors || await this.checkWebfeatureUseCounter(field);
} else if (field.name === 'ot_chromium_trial_name') {
hasErrors = hasErrors || await this.checkChromiumTrialName(field);
} else if (field.name === 'ot_has_third_party_support') {
hasErrors = hasErrors || await this.checkThirdPartySupport(field);
} else if (field.name === 'ot_is_critical_trial') {
hasErrors = hasErrors || await this.checkCriticalTrial(field);
}
}
return hasErrors;
}

async handleFormSubmit(e) {
e.preventDefault();
// If registration approvals is not enabled, ignore all fields related to that setting.
if (!this.showApprovalsFields) {
Expand All @@ -189,6 +328,14 @@ export class ChromedashOTCreationPage extends LitElement {
});
}

const hasErrors = await this.handleChromiumChecks();
this.requestUpdate();
if (hasErrors) {
showToastMessage(
'Some issues were found with the given inputs. Check input errors and try again.');
return;
}

const featureSubmitBody = formatFeatureChanges(this.fieldValues, this.featureId);
// We only need the single stage changes.
const stageSubmitBody = featureSubmitBody.stages[0];
Expand Down Expand Up @@ -254,6 +401,7 @@ export class ChromedashOTCreationPage extends LitElement {
name=${fieldInfo.name}
index=${i}
value=${fieldInfo.value}
.checkMessage=${fieldInfo.checkMessage}
.fieldValues=${this.fieldValues}
.shouldFadeIn=${shouldFadeIn}
@form-field-update="${this.handleFormFieldUpdate}">
Expand Down
15 changes: 11 additions & 4 deletions client-src/elements/form-field-specs.js
Original file line number Diff line number Diff line change
Expand Up @@ -1242,7 +1242,10 @@ export const ALL_FIELDS = {
help_text: html`
Whether this trial supports third party origins. See
<a href="https://web.dev/third-party-origin-trials/">this article</a>
for more information.`,
for more information. The feature should have "origin_trial_allows_third_party"
set to "true" in <a target="_blank"
href="https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/renderer/platform/runtime_enabled_features.json5"
>runtime_enabled_features.json5</a>`,
},

'ot_is_critical_trial': {
Expand All @@ -1252,7 +1255,10 @@ export const ALL_FIELDS = {
help_text: html`
See <a href="https://goto.google.com/running-an-origin-trial"
>go/running-an-origin-trial</a>
for criteria and additional process requirements.`,
for criteria and additional process requirements.
The feature name must be added to the "kHasExpiryGracePeriod" array in <a target="_blank"
href="https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/common/origin_trials/manual_completion_origin_trial_features.cc"
>manual_completion_origin_trial_features.cc</a>`,
},

'ot_is_deprecation_trial': {
Expand Down Expand Up @@ -1283,8 +1289,9 @@ export const ALL_FIELDS = {
label: 'WebFeature UseCounter name',
help_text: html`
For measuring usage, this must be a single named value from the
WebFeature enum, e.g. kWorkerStart. See
<a href="https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom"
WebFeature enum, e.g. kWorkerStart. The use counter must be landed in
<a target="_blank"
href="https://source.chromium.org/chromium/chromium/src/+/main:third_party/blink/public/mojom/use_counter/metrics/web_feature.mojom"
>web_feature.mojom</a>.`,
},

Expand Down
5 changes: 2 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@
"@polymer/iron-collapse": "^3.0.1",
"@polymer/iron-icon": "^3.0.1",
"@polymer/iron-iconset-svg": "^3.0.1",
"json5": "^2.2.3",
"lit": "^3",
"node-fetch": ">=3.3.2",
"page": "^1.11.6",
Expand Down

0 comments on commit ac2413b

Please sign in to comment.