In a previous post, we described how repositories were migrated from Bitbucket Cloud to GitHub Cloud while preserving full Git history, including branches, tags, and submodule references. That migration established a solid foundation, but moving repositories alone is only part of a successful transition.
This article continues the journey by focusing on securely updating project dependencies after the move to GitHub. Ensuring that dependencies are handled correctly is essential for keeping builds stable and CI pipelines running reliably throughout the migration process.
Once repositories are in place, all project-related dependencies must be reviewed and updated where necessary. In this case, the projects rely on Yocto, an open-source collaboration project that provides tools, templates, and methods for building custom Linux-based Linux systems for embedded products across different hardware architectures.

Identifying Insecure Dependency Fetching Methods
During the dependency review, we identified that several Yocto recipes were relying on the Git fetcher over HTTPS, with hardcoded credentials embedded directly in the recipe. These credentials appeared both in the SRC_URI variable and in custom functions responsible for cloning submodules.
A simplified example of such a recipe looked like this:
DESCRIPTION = "Example Service for Embedded System"
LICENSE = "MIT"
BRANCH = "master"
SRC_URI = "git://bitbucket.org/organization/example_service.git;protocol=https;user=<username>:<hardcoded_token>;branch=${BRANCH}"
SRCREV = "<commit_hash>"
do_configure_prepend() {
cd ${WORKDIR}/git
# Clone submodule 1 using HTTPS and hardcoded token
rm -rf submodule1
git clone https://<username>:<hardcoded_token>@bitbucket.org/organization/submodule1.git submodule1
cd submodule1
git checkout <version>
# Clone submodule 2 using HTTPS and hardcoded token
cd ${WORKDIR}/git
rm -rf submodule2
git clone https://<username>:<hardcoded_token>@bitbucket.org/organization/submodule2.git submodule2
}
This approach introduces multiple risks:
- Credentials are exposed in plain text
- Tokens may expire or be revoked after migration
- Fetch steps can fail in automated CI pipelines
- Security best practices are not met
For a long-term, scalable CI/CD setup, this method is neither secure nor reliable.
Migrating Dependencies to SSH-Based Authentication
To improve security and ensure seamless automation, all affected recipes were updated to use SSH-based authentication instead of HTTPS. This removes the need for embedded tokens and aligns better with automated build environments.
The updated recipe looks like this:
DESCRIPTION = "Example Service for Embedded System"
LICENSE = "MIT"
BRANCH = "master"
SRC_URI = "git://git@github.com/organization/example_service.git;protocol=ssh;branch=${BRANCH}"
SRCREV = "<commit_hash>"
do_configure_prepend() {
cd ${WORKDIR}/git
# Clone submodule 1 securely over SSH
rm -rf submodule1
git clone git@github.com:organization/submodule1.git submodule1
cd submodule1
git checkout <version>
# Clone submodule 2 securely over SSH
cd ${WORKDIR}/git
rm -rf submodule2
git clone git@github.com:organization/submodule2.git submodule2
}
With this change:
- Credentials are no longer exposed
- Dependency fetching works reliably in CI
- Both repositories and submodules are fetched securely over SSH
Enabling Secure SSH Access in CI Pipelines
To support SSH-based dependency fetching, the CI environment must have access to a private SSH key. When BitBake executes these recipes, it uses this key to authenticate against GitHub for all referenced repositories and submodules.
The corresponding public key must be associated with a GitHub account that has access to all required repositories.
It’s important to note that a single SSH key is sufficient. As long as the linked GitHub account has the correct permissions, the same key can be used across multiple repositories and submodules.
To avoid SSH verification issues, GitHub should also be configured as a trusted host:
ssh-keyscan github.com >> $HOME/.ssh/known_hosts
Example: GitHub Actions Pipeline Configuration
In this setup, the build runs inside a Docker container, so the container must mount the host’s .ssh directory. This allows BitBake to access the SSH key during fetch operations.
Below is an example GitHub Actions pipeline used in this scenario:
name: Build Embedded Project
on:
push:
branches:
- master
- 'release/*'
- 'feature/*'
workflow_dispatch:
permissions:
id-token: write
contents: read
env:
DOWNLOAD_DIR: /opt/build_dir
BRANCH: ${{ github.ref_name }}
jobs:
build:
runs-on: [self-hosted, linux, x64]
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up SSH key
run: |
mkdir -p $HOME/.ssh
echo "${{ secrets.SSH_PRIVATE_KEY }}" > $HOME/.ssh/id_ed25519
chmod 600 $HOME/.ssh/id_ed25519
ssh-keyscan github.com >> $HOME/.ssh/known_hosts
ssh -T git@github.com || true
- name: Prepare build environment
run: |
make -f docker.mk cleanup DOWNLOAD_DIR=$DOWNLOAD_DIR
- name: Build project
run: |
make -f docker.mk DOWNLOAD_DIR=$DOWNLOAD_DIR
- name: Upload build artifacts
uses: actions/upload-artifact@v4
with:
name: project-build
path: |
$DOWNLOAD_DIR/output/*.tar.gz
$DOWNLOAD_DIR/output/*.ipk
In the Set up SSH key step, the pipeline retrieves the private key from GitHub Secrets, configures GitHub as a trusted host, and verifies authentication. This ensures that all repositories and submodules defined in the BitBake recipes can be accessed securely during the build.
What’s Next: Modernizing CI/CD with GitHub Actions
This concludes the current stage of our migration journey. With repositories migrated, dependencies securely updated, and build pipelines stabilized, the focus now shifts to modernizing CI/CD workflows.
In the next article, we’ll focus on:
- Translating existing Bash scripts and Jenkins pipelines into GitHub Actions
- Standardizing and unifying CI/CD workflows under a single platform
- Improving maintainability and reducing pipeline complexity
Stay tuned for the next part of the series.
Check out more of our blog posts here.