diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml new file mode 100644 index 00000000000000..c3928984ab13c3 --- /dev/null +++ b/.github/workflows/pr.yml @@ -0,0 +1,283 @@ +name: Code Reviews +on: + pull_request: + branches: + - main + types: + - opened + - reopened + - synchronize + - ready_for_review + +jobs: + conditional_review: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 1000 + + - name: Define Upstream Repository and Branch + id: upstream_config + run: | + echo "upstream_repo_url=https://github.com/chromium/chromium.git" >> $GITHUB_OUTPUT + echo "upstream_branch_name=main" >> $GITHUB_OUTPUT + + - name: Check Commit Origin Against Upstream + id: commit_origin_check + run: | + # Ensure script exits on error by default; we will manage specific command failures. + set -e + + UPSTREAM_REPO_URL="${{ steps.upstream_config.outputs.upstream_repo_url }}" + UPSTREAM_BRANCH_NAME="${{ steps.upstream_config.outputs.upstream_branch_name }}" + + PR_BASE_COMMIT_SHA="${{ github.event.pull_request.base.sha }}" + PR_HEAD_SHA="${{ github.event.pull_request.head.sha }}" + + # Set actual fetch depth for logging. + # If you make fetch-depth a workflow input like 'inputs.checkout_fetch_depth', use that here. + # Otherwise, ensure this matches the value in your 'actions/checkout' step. + ACTUAL_FETCH_DEPTH="1000" # As per your last log for this PR + + echo "--- Git Diagnostics ---" + echo "Current fetch-depth for actions/checkout is $ACTUAL_FETCH_DEPTH." + echo "PATH is: $PATH" + echo "Checking for timeout command..." + if ! which timeout > /dev/null; then + echo "Error: 'timeout' command not found in PATH." + # As a fallback, try a common path if 'which' fails or PATH is minimal + if [ -x "/usr/bin/timeout" ]; then + echo "Found timeout at /usr/bin/timeout." + TIMEOUT_CMD="/usr/bin/timeout" + else + echo "FATAL: 'timeout' command is not available. Cannot proceed safely with merge-base." + exit 1 + fi + else + TIMEOUT_CMD="timeout" # Use 'timeout' if found in PATH + echo "'timeout' command found in PATH." + fi + $TIMEOUT_CMD --version || (echo "Error: '$TIMEOUT_CMD --version' failed." && exit 1) + echo "Timeout command seems available and runnable." + + echo "Attempting to deepen fetch for specific SHAs (safeguard)..." + git fetch origin --no-tags --depth=5 "$PR_BASE_COMMIT_SHA" || echo "Warning: Deepening fetch for PR_BASE_COMMIT_SHA ($PR_BASE_COMMIT_SHA) had no effect or failed (might be ok if SHA is already well-fetched)." + git fetch origin --no-tags --depth=5 "$PR_HEAD_SHA" || echo "Warning: Deepening fetch for PR_HEAD_SHA ($PR_HEAD_SHA) had no effect or failed." + echo "-------------------------" + + echo "Upstream Repository URL: $UPSTREAM_REPO_URL" + echo "Target Upstream Branch for Comparison: $UPSTREAM_BRANCH_NAME" + echo "PR Base Commit SHA (from event.pull_request.base.sha): $PR_BASE_COMMIT_SHA" + echo "PR Head SHA (from event.pull_request.head.sha): $PR_HEAD_SHA" + + echo "Verifying PR_BASE_COMMIT_SHA ($PR_BASE_COMMIT_SHA) is a valid commit..." + git rev-parse --verify "$PR_BASE_COMMIT_SHA^{commit}" || (echo "Error: PR_BASE_COMMIT_SHA '$PR_BASE_COMMIT_SHA' could not be resolved." && exit 1) + + echo "Verifying PR_HEAD_SHA ($PR_HEAD_SHA) is a valid commit..." + git rev-parse --verify "$PR_HEAD_SHA^{commit}" || (echo "Error: PR_HEAD_SHA '$PR_HEAD_SHA' could not be resolved." && exit 1) + + # Add upstream remote + if ! git remote | grep -q '^upstream$'; then + echo "Adding remote 'upstream' for $UPSTREAM_REPO_URL" + git remote add upstream "$UPSTREAM_REPO_URL" + else + echo "Remote 'upstream' already exists. Setting URL." + git remote set-url upstream "$UPSTREAM_REPO_URL" + fi + echo "Fetching from upstream remote (target branch: $UPSTREAM_BRANCH_NAME)..." + git fetch upstream "$UPSTREAM_BRANCH_NAME" --no-tags --depth=1000 + UPSTREAM_BRANCH_HEAD_REF="refs/remotes/upstream/$UPSTREAM_BRANCH_NAME" + echo "Successfully fetched $UPSTREAM_BRANCH_HEAD_REF" + + echo "Attempting to run: $TIMEOUT_CMD 300s git merge-base $PR_BASE_COMMIT_SHA $PR_HEAD_SHA" + MERGE_BASE_OUTPUT="" + MERGE_BASE_STATUS=0 # Default to success + + # Execute the command and explicitly manage its potential failure + if MERGE_BASE_OUTPUT=$($TIMEOUT_CMD 300s git merge-base "$PR_BASE_COMMIT_SHA" "$PR_HEAD_SHA" 2>&1); then + MERGE_BASE_STATUS=0 + echo "git merge-base command itself reported success (exit status 0)." + else + MERGE_BASE_STATUS=$? # Capture actual exit status from timeout or git merge-base + echo "git merge-base command (or timeout wrapper) reported failure. Captured status: $MERGE_BASE_STATUS." + fi + + echo "Completed git merge-base attempt. Raw Status: $MERGE_BASE_STATUS. Raw Output: [$MERGE_BASE_OUTPUT]" + + # Now check the status + if [ $MERGE_BASE_STATUS -eq 124 ]; then + echo "Error: 'git merge-base' command TIMED OUT after 5 minutes (status 124 from timeout command)." + echo "This means finding the common ancestor is taking an exceptionally long time, likely due to very deep or complex history not fully covered by the current fetch-depth ($ACTUAL_FETCH_DEPTH)." + echo "RECOMMENDATION: The most reliable solution is 'fetch-depth: 0' in 'actions/checkout' for full history, or a significantly larger specific depth if '0' is too slow." + echo "For safety, this PR will be marked as requiring review." + echo "require_review=true" >> $GITHUB_OUTPUT + exit 0 + elif [ $MERGE_BASE_STATUS -ne 0 ]; then + echo "Error: 'git merge-base' command FAILED with status $MERGE_BASE_STATUS (not a timeout)." + echo "Command output (if any) from git merge-base: $MERGE_BASE_OUTPUT" + echo "This critical failure means a common ancestor could not be found between the PR's base commit ($PR_BASE_COMMIT_SHA) and its head commit ($PR_HEAD_SHA), or another git error occurred." + echo "The MOST LIKELY CAUSE (if output is empty or indicates no common ancestor) is that the history fetched by 'actions/checkout' (current fetch-depth: $ACTUAL_FETCH_DEPTH) is too shallow." + echo "RECOMMENDATION: Significantly increase 'fetch-depth' in 'actions/checkout'. Try a much larger value, or use '0' for full history." + echo "For safety, this PR will be marked as requiring review." + echo "require_review=true" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "git merge-base command seems to have succeeded with status 0." + # If successful, MERGE_BASE_OUTPUT contains the SHA. + MERGE_BASE=$(echo "$MERGE_BASE_OUTPUT" | awk '{print $1}') + + if [ -z "$MERGE_BASE" ]; then + echo "Error: Merge base is empty even though git merge-base reported success (status 0)." + echo "This is unexpected. Output from merge-base was: '$MERGE_BASE_OUTPUT'" + echo "For safety, requiring review." + echo "require_review=true" >> $GITHUB_OUTPUT + exit 0 + fi + + echo "Merge Base for PR commits: $MERGE_BASE" + + PR_COMMIT_SHAS=$(git log "$MERGE_BASE".."$PR_HEAD_SHA" --pretty=format:"%H" --no-merges) + + if [ -z "$PR_COMMIT_SHAS" ]; then + echo "No new authored commits found in PR range ($MERGE_BASE..$PR_HEAD_SHA)." + echo "No local review required by this check." + echo "require_review=false" >> $GITHUB_OUTPUT + exit 0 + fi + echo "Commit SHAs in PR to verify against upstream ($UPSTREAM_BRANCH_HEAD_REF):" + echo "$PR_COMMIT_SHAS" + + ALL_COMMITS_ARE_UPSTREAM=true + for commit_sha in $PR_COMMIT_SHAS; do + echo "Verifying commit $commit_sha against $UPSTREAM_BRANCH_HEAD_REF..." + if git merge-base --is-ancestor "$commit_sha" "$UPSTREAM_BRANCH_HEAD_REF"; then + echo "Commit $commit_sha FOUND in $UPSTREAM_BRANCH_HEAD_REF." + else + echo "Commit $commit_sha NOT FOUND in $UPSTREAM_BRANCH_HEAD_REF. This PR contains local/modified changes." + ALL_COMMITS_ARE_UPSTREAM=false + break + fi + done + + if [[ "$ALL_COMMITS_ARE_UPSTREAM" == "true" ]]; then + echo "All commits in this PR appear to originate from the upstream branch ($UPSTREAM_BRANCH_NAME)." + echo "require_review=false" >> $GITHUB_OUTPUT + else + echo "This PR contains commits not found on the upstream branch ($UPSTREAM_BRANCH_NAME). Internal review required." + echo "require_review=true" >> $GITHUB_OUTPUT + fi + + - name: Determine Review Requirement and Add Labels + id: review_decision_and_labeling + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const requireReviewOutputFromCommitCheck = ${{ steps.commit_origin_check.outputs.require_review || 'false' }}; + const prRequiresReview = requireReviewOutputFromCommitCheck === 'true'; + + const prNumber = context.issue.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + let labelToAdd = ''; + let labelToRemove = ''; + + console.log(`Output from commit_origin_check (require_review string): '${requireReviewOutputFromCommitCheck}'`); + console.log(`Interpreted as prRequiresReview (boolean): ${prRequiresReview}`); + + if (prRequiresReview) { + console.log("Decision: PR contains local/modified changes. Internal review required."); + labelToAdd = 'review-required'; + labelToRemove = 'upstream-sync'; + } else { + console.log("Decision: PR is purely upstream. No internal review required by this check."); + labelToAdd = 'upstream-sync'; + labelToRemove = 'review-required'; + } + + core.setOutput('require_review', prRequiresReview.toString()); + + if (labelToAdd) { + try { + await github.rest.issues.addLabels({ owner, repo, issue_number: prNumber, labels: [labelToAdd] }); + console.log(`Successfully added label: ${labelToAdd}`); + } catch (error) { + core.setFailed(`Error adding label ${labelToAdd}: ${error.message}`); // Fail the step on error + return; // Exit script + } + } + + if (labelToRemove) { + try { + const { data: existingLabels } = await github.rest.issues.listLabelsOnIssue({ owner, repo, issue_number: prNumber }); + const labelExists = existingLabels.some(label => label.name === labelToRemove); + + if (labelExists) { + await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: labelToRemove }); + console.log(`Successfully removed label: ${labelToRemove}`); + } else { + console.log(`Label ${labelToRemove} not found on PR, no need to remove.`); + } + } catch (error) { + console.warn(`Warning removing label ${labelToRemove}: ${error.message}`); // Don't fail for removal issues + } + } + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Enforce Review + id: enforce_review + if: always() + uses: actions/github-script@v7 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const prNumber = context.issue.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + const reviewCompletedLabel = 'review-completed'; + const upstreamSyncLabel = 'upstream-sync'; + const reviewRequiredLabel = 'review-required'; + + + const reviewDecisionOutput = '${{ steps.review_decision_and_labeling.outputs.require_review }}'; + const needsReviewBasedOnCommits = reviewDecisionOutput === 'true'; + + console.log(`Decision from labeling step (needsReviewBasedOnCommits): ${needsReviewBasedOnCommits}`); + + const { data: labelsOnIssue } = await github.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number: prNumber, + }); + + const hasReviewCompletedLabel = labelsOnIssue.some(label => label.name === reviewCompletedLabel); + const hasUpstreamSyncLabel = labelsOnIssue.some(label => label.name === upstreamSyncLabel); + const hasReviewRequiredLabel = labelsOnIssue.some(label => label.name === reviewRequiredLabel); + + if (hasReviewCompletedLabel) { + console.log(`Review confirmed: PR has the '${reviewCompletedLabel}' label. Workflow check passed.`); + if (hasReviewRequiredLabel) { + try { + await github.rest.issues.removeLabel({ owner, repo, issue_number: prNumber, name: reviewRequiredLabel }); + console.log(`Cleaned up '${reviewRequiredLabel}' label after review completion.`); + } catch (error) { + console.warn(`Could not remove '${reviewRequiredLabel}' label during cleanup: ${error.message}`); + } + } + return; + } + + if (hasUpstreamSyncLabel && !needsReviewBasedOnCommits) { + console.log(`PR is an upstream sync and does not require further review by this action (label '${upstreamSyncLabel}' present, commit check confirms no local changes). Workflow check passed.`); + return; + } + + if (needsReviewBasedOnCommits) { + console.log(`Internal review is required (PR contains local/modified commits or commit check decided so) AND '${reviewCompletedLabel}' label is NOT present. Failing check.`); + core.setFailed(`Review required: PR contains local/modified commits (or labeling step determined need for review) and lacks '${reviewCompletedLabel}' label.`); + exit 1; + } \ No newline at end of file diff --git a/DEPS b/DEPS index 75e932c37cfbf1..78be838c464de9 100644 --- a/DEPS +++ b/DEPS @@ -34,6 +34,7 @@ gclient_gn_args_file = 'src/build/config/gclient_args.gni' gclient_gn_args = [ + 'build_with_hopium', 'build_with_chromium', 'checkout_android', 'checkout_android_prebuilts_build_tools', @@ -51,6 +52,9 @@ gclient_gn_args = [ vars = { + # Build hopium tsec brand + 'build_with_hopium': False, + # Variable that can be used to support multiple build scenarios, like having # Chromium specific targets in a client project's GN file or sync dependencies # conditionally etc. @@ -306,6 +310,7 @@ vars = { 'skia_git': 'https://skia.googlesource.com', 'swiftshader_git': 'https://swiftshader.googlesource.com', 'webrtc_git': 'https://webrtc.googlesource.com', + 'hopium_git': 'git@github.com:protectednet', 'betocore_git': 'https://beto-core.googlesource.com', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 @@ -547,6 +552,22 @@ allowed_hosts = [ ] deps = { + 'src/hopium/tslib_hopium': { + 'url': Var('hopium_git') + '/tslib_hopium.git' + '@' + '686d3f51ebf70ba8097de852a90b0ef710dcea76', + 'condition': 'build_with_hopium', + }, + 'src/hopium/tsec_branding': { + 'url': Var('hopium_git') + '/tsec_branding.git' + '@' + '187d01930b937ea91248da84ba73276a86bc4cc1', + 'condition': 'build_with_hopium', + }, + 'src/third_party/poco/src': { + 'url': 'https://github.com/pocoproject/poco.git@poco-1.12.4-release', + 'condition': 'build_with_hopium', + }, + 'src/third_party/openssl/src': { + 'url': 'https://github.com/openssl/openssl.git@openssl-3.1.1', + 'condition': 'build_with_hopium', + }, 'src/third_party/clang-format/script': Var('chromium_git') + '/external/github.com/llvm/llvm-project/clang/tools/clang-format.git@' + diff --git a/cloudbuild.yaml b/cloudbuild.yaml new file mode 100644 index 00000000000000..cad2f6af898974 --- /dev/null +++ b/cloudbuild.yaml @@ -0,0 +1,167 @@ +# Set build timeout to 5 hours rather than the default of 10 mins +timeout: 18000s + +options: + pool: + name: 'projects/protected-app-builds/locations/us-east4/workerPools/e2-standard-32-private-pool' + logging: 'CLOUD_LOGGING_ONLY' + +steps: + # 1. Prepare the workspace + - name: gcr.io/cloud-builders/gcloud + id: 'sshkey' + args: + - kms + - decrypt + - "--plaintext-file=/root/.ssh/id_rsa" + - "--ciphertext-file=id_rsa.enc" + - "--location=global" + - "--keyring=builder-keyring" + - "--key=ssh-key" + - "--project=protected-registry" + volumes: + - name: ssh + path: "/root/.ssh" + + - name: 'gcr.io/protected-app-builds/totalbrowser-builder:1.0.9' + id: 'prepare' + waitFor: [ 'sshkey' ] + entrypoint: 'bash' + args: + - '-c' + - | + set -e + chmod 0600 /root/.ssh/id_rsa + + echo 'Host github.com + HostName github.com + IdentityFile /root/.ssh/id_rsa + User git + IdentitiesOnly yes' >> /root/.ssh/config + + ssh-keyscan -H github.com > /root/.ssh/known_hosts + volumes: + - name: ssh + path: "/root/.ssh" + + # 2. Install Depot Tools + - name: 'gcr.io/cloud-builders/git' + id: 'clone-depot-tools' + args: ['clone', 'https://chromium.googlesource.com/chromium/tools/depot_tools.git', '/workspace/depot_tools'] + + # 3. Fetch the Code + - name: 'gcr.io/protected-app-builds/totalbrowser-builder:1.0.9' + id: 'configure-gclient' + waitFor: [ 'clone-depot-tools' ] + entrypoint: 'bash' + args: + - '-c' + - | + set -e + mkdir /workspace/hopium + cd /workspace/hopium + /workspace/depot_tools/gclient config --unmanaged --name src \ + --custom-var build_with_hopium=True \ + --custom-var checkout_pgo_profiles=True \ + git@github.com:protectednet/hopium.git + + - name: 'gcr.io/protected-app-builds/totalbrowser-builder:1.0.9' + id: 'sync-deps' + waitFor: [ 'configure-gclient' ] + entrypoint: 'bash' + args: + - '-c' + - | + set -e + cd /workspace/hopium + /workspace/depot_tools/gclient sync -j 8 -v -r $TAG_NAME + volumes: + - name: ssh + path: "/root/.ssh" + + - name: 'gcr.io/protected-app-builds/totalbrowser-builder:1.0.9' + id: 'checkout-branch' + waitFor: [ 'sync-deps' ] + entrypoint: 'bash' + args: + - '-c' + - | + set -e + cd /workspace/hopium/src + git checkout $TAG_NAME + /workspace/depot_tools/gclient sync -D + volumes: + - name: ssh + path: "/root/.ssh" + + # 4. Configure & Build + - name: 'gcr.io/protected-app-builds/totalbrowser-builder:1.0.9' + id: 'configure-build' + waitFor: [ 'checkout-branch' ] + entrypoint: 'bash' + args: + - '-c' + - | + # Set EDITOR to a command that does nothing and exits successfully + export EDITOR=/bin/true + set -e + cd /workspace/hopium/src + + mkdir -p out/Debug + /workspace/depot_tools/gn args out/Debug <