Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
81 changes: 81 additions & 0 deletions .github/tools/qnx_credential_helper.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
#!/usr/bin/env python3

# *******************************************************************************
# Copyright (c) 2025 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************

import http.cookiejar
import json
import netrc
import os
import sys
import urllib.parse
import urllib.request


def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)


if __name__ == "__main__":
data = json.load(sys.stdin)

if "qnx.com" not in data["uri"]:
eprint("Unsupported domain")
sys.exit(1)
Comment on lines +30 to +34
Comment thread
nradakovic marked this conversation as resolved.

if "SCORE_QNX_USER" in os.environ and "SCORE_QNX_PASSWORD" in os.environ:
login = os.environ["SCORE_QNX_USER"]
password = os.environ["SCORE_QNX_PASSWORD"]
else:
try:
nrc = netrc.netrc()
auth = nrc.authenticators("qnx.com")
if auth:
login, _, password = auth
else:
raise Exception("No credential found for QNX")
except Exception as excp:
eprint(excp)
eprint("Failed getting credentials from .netrc")
sys.exit(1)

data = urllib.parse.urlencode(
{"userlogin": login, "password": password, "UseCookie": "1"}
)
data = data.encode("ascii")

cookie_jar = http.cookiejar.CookieJar()
cookie_processor = urllib.request.HTTPCookieProcessor(cookie_jar)
opener = urllib.request.build_opener(cookie_processor)
urllib.request.install_opener(opener)

r = urllib.request.urlopen("https://www.qnx.com/account/login.html", data)
if r.status != 200:
eprint("Failed to login to QNX")
sys.exit(1)
Comment on lines +62 to +65

Comment thread
nradakovic marked this conversation as resolved.
cookies = {c.name: c.value for c in list(cookie_jar)}
if not "myQNX" in cookies:
eprint("Failed to get myQNX cookie from login page")
sys.exit(1)

myQNX = cookies["myQNX"]
print(
json.dumps(
{
"headers": {
"Cookie": [f"myQNX={myQNX}"],
}
}
)
)
104 changes: 104 additions & 0 deletions .github/workflows/qnx.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# *******************************************************************************
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# See the NOTICE file(s) distributed with this work for additional
# information regarding copyright ownership.
#
# This program and the accompanying materials are made available under the
# terms of the Apache License Version 2.0 which is available at
# https://www.apache.org/licenses/LICENSE-2.0
#
# SPDX-License-Identifier: Apache-2.0
# *******************************************************************************
name: Bazel Build (QNX)
on:
pull_request:
types: [opened, reopened, synchronize]
push:
branches:
- main
merge_group:
types: [checks_requested]
workflow_call:
jobs:
qnx-build:
name: Build and Test ${{ matrix.bazel-config }}
runs-on: ${{ vars.runner_labels_ghub_standard_x64 && fromJSON(vars.runner_labels_ghub_standard_x64) || vars.REPO_RUNNER_LABELS && fromJSON(vars.REPO_RUNNER_LABELS) || 'ubuntu-latest' }}
permissions:
contents: read
pull-requests: read
# Bazel test targets live in the separate `tests` module, so run all Bazel
# commands from that directory. `defaults.run.working-directory` applies to
# `run:` steps only; `uses:` action steps still execute from the repo root.
defaults:
run:
working-directory: ./tests
strategy:
fail-fast: false
matrix:
include:
- bazel-config: x86_64-qnx
bazel-test-target: "//:all_tests"
- bazel-config: aarch64-qnx
bazel-test-target: "//:all_tests"
extra-bazel-test-flags: "--test_timeout=120,600,1800,7200" # Increase test timeout due to QEMU emulation
steps:
- uses: eclipse-score/more-disk-space@6a3b48901846bf7f8cc985925157d71a8973e61f # v1
with:
level: 2
- name: Checkout repository (Handle all events)
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd #v6.0.2
with:
ref: ${{ github.head_ref || github.event.pull_request.head.ref || github.ref }}
repository: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
- name: Setup Bazel with shared caching
uses: bazel-contrib/setup-bazel@c5acdfb288317d0b5c0bbd7a396a3dc868bb0f86 #v0.19.0
with:
disk-cache: ${{ matrix.bazel-config }}
repository-cache: true
bazelisk-cache: true
cache-save: ${{ github.event_name == 'push' }}
- uses: eclipse-score/cicd-actions/unblock-user-namespace-for-linux-sandbox@30ed908edcf367bc38ebff5b386a244f9b6417a7 # 2025-06-04
- name: Setup QNX SDP usage
uses: eclipse-score/cicd-actions/setup-qnx-sdp@a2b3c36fc7d1b9d03880d19935c7ac9cfffe58c6 # 2026-05-19
with:
qnx-license: ${{ secrets.SCORE_QNX_LICENSE }}
qnx-user: ${{ secrets.SCORE_QNX_USER }}
qnx-password: ${{ secrets.SCORE_QNX_PASSWORD }}
qnx-credential-helper: .github/tools/qnx_credential_helper.py
qnx-license-dir: /opt/score_qnx/license
- name: Build with QNX toolchain
run: |
set -euo pipefail

bazel build --config ${{ matrix.bazel-config }} \
--credential_helper=*.qnx.com="${QNX_CREDENTIAL_HELPER}" -- \
//:all_tests
- name: Install qemu
run: |
sudo apt-get update
sudo apt-get install -y qemu-system
- name: Enable KVM group permissions
run: |
echo 'KERNEL=="kvm", GROUP="kvm", MODE="0660", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules
sudo udevadm control --reload-rules
sudo udevadm trigger --name-match=kvm
sudo chown "$USER":kvm /dev/kvm && sudo chmod 0660 /dev/kvm
- name: Test with QNX toolchain
run: |
set -euo pipefail

bazel test --config ${{ matrix.bazel-config }} \
--test_output=errors \
--credential_helper=*.qnx.com="${QNX_CREDENTIAL_HELPER}" ${{ matrix.extra-bazel-test-flags }} -- \
${{ matrix.bazel-test-target }}
- name: Dump test logs on failure
if: failure()
run: |
echo "===== Bazel test logs ====="
# `bazel-testlogs` is a convenience symlink in the workspace root (./tests).
find -L bazel-testlogs -name 'test.log' -print | while read -r log; do
echo ""
echo "----- ${log} -----"
cat "${log}"
done
14 changes: 14 additions & 0 deletions tests/.bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,27 @@ build:x86_64-linux-bp --extra_toolchains=@score_gcc_toolchain_bp//:x86_64-linux
build:x86_64-qnx --config=x86_64-linux
build:x86_64-qnx --platforms=@score_bazel_platforms//:x86_64-qnx-sdp_8.0.0-posix
build:x86_64-qnx --extra_toolchains=@score_qcc_toolchain//:x86_64-qnx-sdp_8.0.0
build:x86_64-qnx --extra_toolchains=@score_qnx_x86_64_ifs_toolchain//:ifs-x86_64-qnx-sdp_8.0.0
# QNX binaries cannot run natively on the x86_64 Linux host; execute them under
# the QNX emulator (requires qemu-system + KVM on the runner).
test:x86_64-qnx --run_under=@score_qnx_unit_tests//src:run_under_qnx
# Only run native (cc) test binaries under the QNX emulator. Host-side tests
# such as the bash-script guardrail cannot execute inside the QNX VM.
test:x86_64-qnx --test_lang_filters=cc

# -------------------------------------------------------------------------------
# Toolchain configuration for aarch64-qnx (target)
# -------------------------------------------------------------------------------
build:aarch64-qnx --config=x86_64-linux
build:aarch64-qnx --platforms=@score_bazel_platforms//:aarch64-qnx-sdp_8.0.0-posix
build:aarch64-qnx --extra_toolchains=@score_qcc_arm_toolchain//:aarch64-qnx-sdp_8.0.0
build:aarch64-qnx --extra_toolchains=@score_qnx_aarch64_ifs_toolchain//:ifs-aarch64-qnx-sdp_8.0.0
# QNX binaries cannot run natively on the x86_64 Linux host; execute them under
# the QNX emulator (requires qemu-system + KVM on the runner).
test:aarch64-qnx --run_under=@score_qnx_unit_tests//src:run_under_qnx
# Only run native (cc) test binaries under the QNX emulator. Host-side tests
# such as the bash-script guardrail cannot execute inside the QNX VM.
test:aarch64-qnx --test_lang_filters=cc

# -------------------------------------------------------------------------------
# Toolchain configuration for aarch64-linux (target)
Expand Down
16 changes: 16 additions & 0 deletions tests/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,19 @@ test_suite(
"//guardrails:no_legacy_features_guard_test",
],
)

# ============================================================================
# Aggregate Test Suite
#
# Combines every test category into a single target. CI should depend on this
# target so new tests only need to be added to the relevant suite above.
# ============================================================================

test_suite(
name = "all_tests",
tests = [
":feature_verification_tests",
":guardrail_tests",
":language_and_standards_tests",
],
)
43 changes: 41 additions & 2 deletions tests/MODULE.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ bazel_dep(name = "rules_go", version = "0.61.1")
# *******************************************************************************
# Common useful functions and rules for Bazel
# *******************************************************************************
bazel_dep(name = "bazel_skylib", version = "1.8.2")
bazel_dep(name = "bazel_skylib", version = "1.9.0")

# *******************************************************************************
# Constraint values for specifying platforms and toolchains
Expand All @@ -39,6 +39,12 @@ bazel_dep(name = "score_bazel_platforms", version = "0.1.2")
bazel_dep(name = "rules_cc", version = "0.2.17")
bazel_dep(name = "googletest", version = "1.17.0")

# *******************************************************************************
# QNX unit-test runner (provides //src:run_under_qnx used to execute QNX test
# binaries under emulation via --run_under on the QNX configs).
# *******************************************************************************
bazel_dep(name = "score_qnx_unit_tests", version = "0.2.0", dev_dependency = True)

# *******************************************************************************
# Set dependency to Bazel C/C++ Toolchain repository - with overriding path
# *******************************************************************************
Expand Down Expand Up @@ -133,7 +139,7 @@ gcc.toolchain(
# *******************************************************************************
gcc.toolchain(
name = "score_qcc_arm_toolchain",
sdp_version = "8.0.0",
sdp_version = "8.0.4",
target_cpu = "aarch64",
target_os = "qnx",
use_default_package = True,
Expand Down Expand Up @@ -170,5 +176,38 @@ use_repo(
"score_gcc_toolchain",
"score_gcc_toolchain_bp",
"score_qcc_arm_toolchain",
"score_qcc_arm_toolchain_pkg",
"score_qcc_toolchain",
"score_qcc_toolchain_pkg",
)

# *******************************************************************************
# Set dependency to Bazel ImageFS repository
# *******************************************************************************
bazel_dep(name = "score_rules_imagefs", version = "0.0.3", dev_dependency = True)

# *******************************************************************************
# Setting ImageFS toolchains (CPU:x86_64|OS:QNX|version(sdp):8.0.0)
# *******************************************************************************
imagefs = use_extension("@score_rules_imagefs//extensions:imagefs.bzl", "imagefs", dev_dependency = True)
imagefs.toolchain(
name = "score_qnx_x86_64_ifs_toolchain",
sdp_to_import = "@score_qcc_toolchain_pkg",
sdp_version = "8.0.0",
target_cpu = "x86_64",
target_os = "qnx",
type = "ifs",
)

# *******************************************************************************
# Setting ImageFS toolchains (CPU:aarch64|OS:QNX|version(sdp):8.0.0)
# *******************************************************************************
imagefs.toolchain(
name = "score_qnx_aarch64_ifs_toolchain",
sdp_to_import = "@score_qcc_arm_toolchain_pkg",
sdp_version = "8.0.0",
target_cpu = "aarch64",
target_os = "qnx",
type = "ifs",
)
use_repo(imagefs, "score_qnx_aarch64_ifs_toolchain", "score_qnx_x86_64_ifs_toolchain")
Loading
Loading