chore(ci): Dependabot, workflow security (#1257)

Co-authored-by: StepSecurity Bot <bot@stepsecurity.io>
Co-authored-by: niStee <52573120+niStee@users.noreply.github.comclear>
Co-authored-by: GideonBear <87426140+GideonBear@users.noreply.github.com>
This commit is contained in:
Nils
2025-08-11 10:24:18 +02:00
committed by GitHub
parent 9048cd8f47
commit 91fc5e3902
28 changed files with 257 additions and 109 deletions

View File

@@ -2,9 +2,23 @@
version: 2 version: 2
updates: updates:
- package-ecosystem: "github-actions" - package-ecosystem: "github-actions"
directory: "/" directory: "/"
schedule: schedule:
# Check for updates to GitHub Actions every week
interval: "weekly" interval: "weekly"
- package-ecosystem: cargo
directory: "/"
schedule:
interval: "weekly"
day: "monday"
time: "06:00"
timezone: "UTC"
versioning-strategy: increase
labels: ["dependencies", "cargo"]
commit-message:
prefix: "deps(cargo)"
include: "scope"
groups:
cargo-minor-patch:
update-types: ["minor", "patch"]

View File

@@ -7,12 +7,15 @@ env:
CARGO_TERM_COLOR: always CARGO_TERM_COLOR: always
permissions:
contents: read
jobs: jobs:
TestConfig: TestConfig:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- run: | - run: |
CONFIG_PATH=~/.config/topgrade.toml; CONFIG_PATH=~/.config/topgrade.toml;
if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi if [ -f "$CONFIG_PATH" ]; then rm $CONFIG_PATH; fi

View File

@@ -6,12 +6,15 @@ on:
name: Check i18n name: Check i18n
permissions:
contents: read
jobs: jobs:
check_locale: check_locale:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Install checker - name: Install checker
# Build it with the dev profile as this is faster and the checker still works # Build it with the dev profile as this is faster and the checker still works

View File

@@ -11,6 +11,9 @@ on:
branches: branches:
- main - main
permissions:
contents: read
jobs: jobs:
lint: lint:
name: DevSkim name: DevSkim
@@ -21,12 +24,12 @@ jobs:
security-events: write security-events: write
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Run DevSkim scanner - name: Run DevSkim scanner
uses: microsoft/DevSkim-Action@v1 uses: microsoft/DevSkim-Action@4b5047945a44163b94642a1cecc0d93a3f428cc6 # v1.0.16
- name: Upload DevSkim scan results to GitHub Security tab - name: Upload DevSkim scan results to GitHub Security tab
uses: github/codeql-action/upload-sarif@v3 uses: github/codeql-action/upload-sarif@v3.29.5
with: with:
sarif_file: devskim-results.sarif sarif_file: devskim-results.sarif

View File

@@ -4,12 +4,15 @@ on:
name: Check SemVer compliance name: Check SemVer compliance
permissions:
contents: read
jobs: jobs:
prepare: prepare:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- uses: actions-rs/toolchain@v1 - uses: actions-rs/toolchain@16499b5e05bf2e26879000db0c1d13f7e13fa3af # v1.0.7
with: with:
toolchain: nightly-2022-08-03 toolchain: nightly-2022-08-03
override: true override: true
@@ -18,7 +21,7 @@ jobs:
semver: semver:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions-rs/cargo@v1 - uses: actions-rs/cargo@844f36862e911db73fe0815f00a4a2602c279505 # v1.0.3
with: with:
command: install command: install
args: --git https://github.com/rust-lang/rust-semverver args: --git https://github.com/rust-lang/rust-semverver

View File

@@ -10,13 +10,16 @@ env:
CROSS_VER: '0.2.5' CROSS_VER: '0.2.5'
CARGO_NET_RETRY: 3 CARGO_NET_RETRY: 3
permissions:
contents: read
jobs: jobs:
fmt: fmt:
name: Rustfmt name: Rustfmt
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Run cargo fmt - name: Run cargo fmt
env: env:
@@ -30,7 +33,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Check if `Step` enum is sorted - name: Check if `Step` enum is sorted
run: | run: |
@@ -47,7 +50,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Check if `Step::run()`'s match is sorted - name: Check if `Step::run()`'s match is sorted
run: | run: |
@@ -96,10 +99,10 @@ jobs:
os: windows-latest os: windows-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4.2.2
- name: Setup Rust Cache - name: Setup Rust Cache
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@98c8021b550208e191a6a3145459bfc9fb29c4c0 # v2.8.0
with: with:
prefix-key: ${{ matrix.target }} prefix-key: ${{ matrix.target }}

View File

@@ -19,6 +19,9 @@ on:
required: true required: true
type: string type: string
permissions:
contents: read
jobs: jobs:
# Publish release files for CD native environments # Publish release files for CD native environments
native_build: native_build:
@@ -38,7 +41,7 @@ jobs:
platform: [ ubuntu-22.04, macos-latest, macos-13, windows-latest ] platform: [ ubuntu-22.04, macos-latest, macos-13, windows-latest ]
runs-on: ${{ matrix.platform }} runs-on: ${{ matrix.platform }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- name: Install needed components - name: Install needed components
run: | run: |
@@ -121,13 +124,13 @@ jobs:
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
with: with:
tag_name: ${{ steps.determine_tag_name.outputs.tag_name }} tag_name: ${{ steps.determine_tag_name.outputs.tag_name }}
files: assets/* files: assets/*
- name: Generate artifact attestations - name: Generate artifact attestations
uses: actions/attest-build-provenance@v2 uses: actions/attest-build-provenance@v2.4.0
with: with:
subject-path: assets/* subject-path: assets/*
@@ -153,7 +156,7 @@ jobs:
] ]
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- name: Install needed components - name: Install needed components
run: | run: |
@@ -179,7 +182,7 @@ jobs:
run: rustup target add ${{ matrix.target }} run: rustup target add ${{ matrix.target }}
- name: install cross - name: install cross
uses: taiki-e/install-action@v2 uses: taiki-e/install-action@aa2649f25ee7099207734772f5393fd30167cb73 # v2.58.0
with: with:
tool: cross@0.2.5 tool: cross@0.2.5
@@ -238,12 +241,12 @@ jobs:
- name: Release - name: Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2.3.2
with: with:
tag_name: ${{ steps.determine_tag_name.outputs.tag_name }} tag_name: ${{ steps.determine_tag_name.outputs.tag_name }}
files: assets/* files: assets/*
- name: Generate artifact attestations - name: Generate artifact attestations
uses: actions/attest-build-provenance@v2 uses: actions/attest-build-provenance@v2.4.0
with: with:
subject-path: assets/* subject-path: assets/*

22
.github/workflows/dependency-review.yml vendored Normal file
View File

@@ -0,0 +1,22 @@
# Dependency Review Action
#
# This Action will scan dependency manifest files that change as part of a Pull Request,
# surfacing known-vulnerable versions of the packages declared or updated in the PR.
# Once installed, if the workflow run is marked as required,
# PRs introducing known-vulnerable packages will be blocked from merging.
#
# Source repository: https://github.com/actions/dependency-review-action
name: 'Dependency Review'
on: [pull_request]
permissions:
contents: read
jobs:
dependency-review:
runs-on: ubuntu-latest
steps:
- name: 'Checkout Repository'
uses: actions/checkout@v4.2.2
- name: 'Dependency Review'
uses: actions/dependency-review-action@da24556b548a50705dd671f47852072ea4c105d9 # v4.7.1

View File

@@ -15,6 +15,9 @@ on:
required: false required: false
type: string type: string
permissions:
contents: read
jobs: jobs:
aur-publish: aur-publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest

View File

@@ -10,16 +10,19 @@ on:
tags: tags:
- "v*" - "v*"
permissions:
contents: read
jobs: jobs:
homebrew-publish: homebrew-publish:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Set up Homebrew - name: Set up Homebrew
id: set-up-homebrew id: set-up-homebrew
uses: Homebrew/actions/setup-homebrew@master uses: Homebrew/actions/setup-homebrew@24a0b15df658487e137fcd20fba32757d41a9411 # master
- name: Cache Homebrew Bundler RubyGems - name: Cache Homebrew Bundler RubyGems
id: cache id: cache
uses: actions/cache@v4 uses: actions/cache@v4.2.3
with: with:
path: ${{ steps.set-up-homebrew.outputs.gems-path }} path: ${{ steps.set-up-homebrew.outputs.gems-path }}
key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }} key: ${{ runner.os }}-rubygems-${{ steps.set-up-homebrew.outputs.gems-hash }}
@@ -29,7 +32,7 @@ jobs:
if: steps.cache.outputs.cache-hit != 'true' if: steps.cache.outputs.cache-hit != 'true'
run: brew install-bundler-gems run: brew install-bundler-gems
- name: Bump formulae - name: Bump formulae
uses: Homebrew/actions/bump-packages@master uses: Homebrew/actions/bump-packages@24a0b15df658487e137fcd20fba32757d41a9411 # master
continue-on-error: true continue-on-error: true
with: with:
# Custom GitHub access token with only the 'public_repo' scope enabled # Custom GitHub access token with only the 'public_repo' scope enabled

View File

@@ -15,16 +15,16 @@ jobs:
matrix: matrix:
target: [x86_64, x86, aarch64] target: [x86_64, x86, aarch64]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- name: Build wheels - name: Build wheels
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
args: --release --out dist args: --release --out dist
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
manylinux: auto manylinux: auto
- name: Upload wheels - name: Upload wheels
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.2
with: with:
name: wheels-linux-${{ matrix.target }} name: wheels-linux-${{ matrix.target }}
path: dist path: dist
@@ -35,15 +35,15 @@ jobs:
matrix: matrix:
target: [x64, x86] target: [x64, x86]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- name: Build wheels - name: Build wheels
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
args: --release --out dist args: --release --out dist
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
- name: Upload wheels - name: Upload wheels
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.2
with: with:
name: wheels-windows-${{ matrix.target }} name: wheels-windows-${{ matrix.target }}
path: dist path: dist
@@ -54,15 +54,15 @@ jobs:
matrix: matrix:
target: [x86_64, aarch64] target: [x86_64, aarch64]
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- name: Build wheels - name: Build wheels
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
args: --release --out dist args: --release --out dist
sccache: ${{ !startsWith(github.ref, 'refs/tags/') }} sccache: ${{ !startsWith(github.ref, 'refs/tags/') }}
- name: Upload wheels - name: Upload wheels
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.2
with: with:
name: wheels-macos-${{ matrix.target }} name: wheels-macos-${{ matrix.target }}
path: dist path: dist
@@ -70,14 +70,14 @@ jobs:
sdist: sdist:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4.2.2
- name: Build sdist - name: Build sdist
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
with: with:
command: sdist command: sdist
args: --out dist args: --out dist
- name: Upload sdist - name: Upload sdist
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4.6.2
with: with:
name: wheels-sdist name: wheels-sdist
path: dist path: dist
@@ -94,15 +94,15 @@ jobs:
# Used to generate artifact attestation # Used to generate artifact attestation
attestations: write attestations: write
steps: steps:
- uses: actions/download-artifact@v4 - uses: actions/download-artifact@v4.3.0
- name: Generate artifact attestation - name: Generate artifact attestation
uses: actions/attest-build-provenance@v2 uses: actions/attest-build-provenance@v2.4.0
with: with:
subject-path: 'wheels-*/*' subject-path: 'wheels-*/*'
- name: Publish to PyPI - name: Publish to PyPI
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@e10f6c464b90acceb5f640d31beda6d586ba7b4a # v1.49.3
env: env:
MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }} MATURIN_PYPI_TOKEN: ${{ secrets.PYPI_API_TOKEN }}
with: with:

View File

@@ -4,11 +4,14 @@ on:
types: [released] types: [released]
workflow_dispatch: workflow_dispatch:
permissions:
contents: read
jobs: jobs:
publish: publish:
runs-on: windows-latest runs-on: windows-latest
steps: steps:
- uses: vedantmgoyal2009/winget-releaser@main - uses: vedantmgoyal2009/winget-releaser@19e706d4c9121098010096f9c495a70a7518b30f # main
with: with:
identifier: topgrade-rs.topgrade identifier: topgrade-rs.topgrade
max-versions-to-keep: 5 # keep only latest 5 versions max-versions-to-keep: 5 # keep only latest 5 versions

76
.github/workflows/scorecards.yml vendored Normal file
View File

@@ -0,0 +1,76 @@
# This workflow uses actions that are not certified by GitHub. They are provided
# by a third-party and are governed by separate terms of service, privacy
# policy, and support documentation.
name: Scorecard supply-chain security
on:
# For Branch-Protection check. Only the default branch is supported. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
branch_protection_rule:
# To guarantee Maintained check is occasionally updated. See
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
schedule:
- cron: '20 7 * * 2'
push:
branches: ["main"]
# Declare default permissions as read only.
permissions: read-all
jobs:
analysis:
name: Scorecard analysis
runs-on: ubuntu-latest
permissions:
# Needed to upload the results to code-scanning dashboard.
security-events: write
# Needed to publish results and get a badge (see publish_results below).
id-token: write
contents: read
actions: read
# To allow GraphQL ListCommits to work
issues: read
pull-requests: read
# To detect SAST tools
checks: read
steps:
- name: "Checkout code"
uses: actions/checkout@v4.2.2
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
with:
results_file: results.sarif
results_format: sarif
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
# - you want to enable the Branch-Protection check on a *public* repository, or
# - you are installing Scorecards on a *private* repository
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
# Public repositories:
# - Publish results to OpenSSF REST API for easy access by consumers
# - Allows the repository to include the Scorecard badge.
# - See https://github.com/ossf/scorecard-action#publishing-results.
# For private repositories:
# - `publish_results` will always be set to `false`, regardless
# of the value entered here.
publish_results: true
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@v4.6.2
with:
name: SARIF file
path: results.sarif
retention-days: 5
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@v3.29.5
with:
sarif_file: results.sarif

14
.pre-commit-config.yaml Normal file
View File

@@ -0,0 +1,14 @@
repos:
- repo: https://github.com/gitleaks/gitleaks
rev: v8.16.3
hooks:
- id: gitleaks
- repo: https://github.com/shellcheck-py/shellcheck-py
rev: v0.10.0.1
hooks:
- id: shellcheck
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: end-of-file-fixer
- id: trailing-whitespace

View File

@@ -62,8 +62,3 @@
> You can also take a look at the official tutorial [Publishing on crates.io][doc] > You can also take a look at the official tutorial [Publishing on crates.io][doc]
> >
> [doc]: https://doc.rust-lang.org/cargo/reference/publishing.html > [doc]: https://doc.rust-lang.org/cargo/reference/publishing.html

View File

@@ -8,4 +8,3 @@ We only support the latest major version and each subversion.
| -------- | ------------------ | | -------- | ------------------ |
| 16.0.x | :white_check_mark: | | 16.0.x | :white_check_mark: |
| < 16.0 | :x: | | < 16.0 | :x: |

View File

@@ -1,4 +1,5 @@
#!/usr/bin/env sh #!/usr/bin/env bash
build_function() { build_function() {
rustup update rustup update
cargo install cross cargo install cross
@@ -20,7 +21,7 @@ build_function() {
package_function() { package_function() {
cd build cd build || exit 1
mkdir x86_64-unknown-linux-gnu/ mkdir x86_64-unknown-linux-gnu/
mkdir x86_64-unknown-linux-musl/ mkdir x86_64-unknown-linux-musl/
mkdir x86_64-unknown-freebsd/ mkdir x86_64-unknown-freebsd/
@@ -35,28 +36,28 @@ package_function() {
cp ../target/aarch64-unknown-linux-musl/release/topgrade aarch64-unknown-linux-musl/topgrade cp ../target/aarch64-unknown-linux-musl/release/topgrade aarch64-unknown-linux-musl/topgrade
cp ../target/x86_64-pc-windows-gnu/release/topgrade.exe x86_64-pc-windows-gnu/topgrade.exe cp ../target/x86_64-pc-windows-gnu/release/topgrade.exe x86_64-pc-windows-gnu/topgrade.exe
cd x86_64-unknown-linux-gnu/ cd x86_64-unknown-linux-gnu/ || exit 1
tar -czf ../topgrade-${ans}-x86_64-linux-gnu.tar.gz topgrade tar -czf "../topgrade-${ans}-x86_64-linux-gnu.tar.gz" topgrade
cd .. cd ..
cd x86_64-unknown-linux-musl cd x86_64-unknown-linux-musl/ || exit 1
tar -czf ../topgrade-${ans}-x86_64-linux-musl.tar.gz topgrade tar -czf "../topgrade-${ans}-x86_64-linux-musl.tar.gz" topgrade
cd .. cd ..
cd x86_64-unknown-freebsd/ cd x86_64-unknown-freebsd/ || exit 1
tar -czf ../topgrade-${ans}-x86_64-freebsd.tar.gz topgrade tar -czf "../topgrade-${ans}-x86_64-freebsd.tar.gz" topgrade
cd .. cd ..
cd aarch64-unknown-linux-gnu/ cd aarch64-unknown-linux-gnu/ || exit 1
tar -czf ../topgrade-${ans}-aarch64-linux-gnu.tar.gz topgrade tar -czf "../topgrade-${ans}-aarch64-linux-gnu.tar.gz" topgrade
cd .. cd ..
cd aarch64-unknown-linux-musl/ cd aarch64-unknown-linux-musl/ || exit 1
tar -czf ../topgrade-${ans}-aarch64-linux-musl.tar.gz topgrade tar -czf "../topgrade-${ans}-aarch64-linux-musl.tar.gz" topgrade
cd .. cd ..
cd x86_64-pc-windows-gnu/ cd x86_64-pc-windows-gnu/ || exit 1
zip -q ../topgrade-${ans}-x86_64-windows.zip topgrade.exe zip -q "../topgrade-${ans}-x86_64-windows.zip" topgrade.exe
cd .. cd ..
cd .. cd ..
@@ -65,17 +66,19 @@ package_function() {
print_checksums() { print_checksums() {
cd build/ cd build/ || exit 1
sha256sum topgrade-${ans}-* sha256sum topgrade-"${ans}"-*
cd ../ cd ../
} }
while true; do while true; do
echo "You should always have a look on scripts you download from the internet." echo "You should always have a look on scripts you download from the internet."
# shellcheck disable=SC2162
read -p "Do you still want to proceed? (y/n) " yn read -p "Do you still want to proceed? (y/n) " yn
echo -n "Input version number: " echo -n "Input version number: "
# shellcheck disable=SC2162
read ans read ans
mkdir build mkdir build

View File

@@ -13,4 +13,3 @@ CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7" CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos" REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7" REDHAT_SUPPORT_PRODUCT_VERSION="7"

View File

@@ -4,4 +4,3 @@ PRETTY_NAME="Manjaro ARM"
ANSI_COLOR="1;32" ANSI_COLOR="1;32"
HOME_URL="https://www.manjaro.org/" HOME_URL="https://www.manjaro.org/"
SUPPORT_URL="https://forum.manjaro.org/c/manjaro-arm/" SUPPORT_URL="https://forum.manjaro.org/c/manjaro-arm/"