Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

v5.10.1 into main #726

Merged
merged 27 commits into from
May 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7f3298a
5.10 updates (#784)
vinnybod Feb 23, 2024
1324e6b
add dependabot for github actions (#776)
vinnybod Feb 23, 2024
36c01fa
Merge branch 'private-main' into 5.10-dev
vinnybod Mar 7, 2024
483c952
fix loading openapi.json (#791)
vinnybod Mar 10, 2024
174b692
Aaronvigal/callback socket message (#794)
vinnybod Mar 10, 2024
6e8eb58
Updated to startup and install (#790)
Cx01N Mar 11, 2024
37ae76a
Updated modules to use suggested values (#793)
Cx01N Mar 11, 2024
a6b7827
Added process spawn bof (#795)
Cx01N Mar 12, 2024
3034816
Change file permissions for empire and listener logs to be non-root (…
Cx01N Mar 29, 2024
82f3f56
Merge pull request #797 from BC-SECURITY/5.10-dev
vinnybod Apr 4, 2024
fe80b30
Added Moriarty module and .NET 4.5 support (#799)
Cx01N Apr 6, 2024
bdb941e
Added keylog, error, and complete task statuses (#798)
Cx01N Apr 7, 2024
58a1446
Bump actions/setup-python from 2 to 5 (#801)
dependabot[bot] Apr 8, 2024
b039d23
Bump actions/checkout from 3 to 4 (#803)
dependabot[bot] Apr 8, 2024
72f434c
Bump thomaseizinger/create-pull-request from 1.0.0 to 1.3.1 (#802)
dependabot[bot] Apr 8, 2024
db06e1c
Prepare release 5.10.0 private
web-flow Apr 8, 2024
7f61055
Merge pull request #805 from BC-SECURITY/release/5.10.0-private
vinnybod Apr 8, 2024
af85868
readded missing .NET 4.5 dlls (#808)
Cx01N Apr 11, 2024
497a913
Bump MishaKav/pytest-coverage-comment from 1.1.48 to 1.1.51 (#807)
dependabot[bot] Apr 15, 2024
1480f3d
Bump tj-actions/changed-files from 29.0.2 to 44.0.0 (#804)
dependabot[bot] Apr 15, 2024
5cf9cf9
Added clr.py to lib.zip for ipy (#809)
Cx01N Apr 15, 2024
7d33f3e
Fix run_as_user and added Starkiller to reset script (#810)
Cx01N Apr 21, 2024
e25b0d5
Bump tj-actions/changed-files from 44.0.0 to 44.3.0 (#813)
dependabot[bot] Apr 26, 2024
1a41069
Prepare release 5.10.1 private
web-flow Apr 26, 2024
4f597c2
Merge pull request #814 from BC-SECURITY/release/5.10.1-private
vinnybod Apr 26, 2024
eba7951
Update starkiller version to v2.8.0
web-flow May 3, 2024
f2a1d64
Merge branch 'main' into release/5.10.1
vinnybod May 3, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
7 changes: 7 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"
target-branch: "private-main"
2 changes: 1 addition & 1 deletion .github/workflows/cherry-pick-main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out sponsor repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: 'BC-Security/Empire-Sponsors'
submodules: 'recursive'
Expand Down
20 changes: 10 additions & 10 deletions .github/workflows/lint-and-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,11 @@ jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: psf/black@23.12.0
- uses: actions/checkout@v4
- uses: psf/black@24.2.0
- name: Run ruff
run: |
pip install ruff==0.1.9
pip install ruff==0.2.1
ruff .
matrix-prep-config:
runs-on: ubuntu-latest
Expand All @@ -40,13 +40,13 @@ jobs:
strategy:
matrix: ${{ fromJson(needs.matrix-prep-config.outputs.config) }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
if: ${{ endsWith(github.repository, 'Empire') }}
with:
submodules: 'recursive'
# token is only needed in sponsors repo because of private submodules
# don't use token in public repo because prs from forks cannot access secrets
- uses: actions/checkout@v3
- uses: actions/checkout@v4
if: ${{ endsWith(github.repository, 'Empire-Sponsors') }}
with:
submodules: 'recursive'
Expand All @@ -57,7 +57,7 @@ jobs:
# Poetry cache depends on OS, Python version and Poetry version.
# https://gist.github.com/gh640/233a6daf68e9e937115371c0ecd39c61
- name: Setup Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
cache: 'poetry'
Expand Down Expand Up @@ -85,7 +85,7 @@ jobs:
DATABASE_USE=sqlite poetry run pytest . -v --runslow
- name: Pytest coverage comment
if: ${{ matrix.python-version == '3.12' }}
uses: MishaKav/[email protected].48
uses: MishaKav/[email protected].51
with:
pytest-coverage-path: ./pytest-coverage.txt
junitxml-path: ./pytest.xml
Expand All @@ -96,7 +96,7 @@ jobs:
runs-on: ubuntu-latest
name: Test Docker Image
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: 'recursive'
token: ${{ secrets.RELEASE_TOKEN }}
Expand Down Expand Up @@ -132,14 +132,14 @@ jobs:
# Parrot disabled for now because the apt repo is having some slowness issues.
# Install is running up way too many minutes.
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: 'recursive'
depth: 0
# To save CI time, only run these tests when the install script or deps changed
- name: Get changed files using defaults
id: changed-files
uses: tj-actions/changed-files@v29.0.2
uses: tj-actions/changed-files@v44.3.0
- name: Build images
if: contains(steps.changed-files.outputs.modified_files, 'setup/install.sh') || contains(steps.changed-files.outputs.modified_files, 'poetry.lock')
run: docker compose -f .github/install_tests/docker-compose-install-tests.yml build --parallel ${{ join(matrix.images, ' ') }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'recursive'
ref: private-main
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/release-private-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- name: Set target branch
run: echo "TARGET_BRANCH=private-main" >> $GITHUB_ENV
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: ${{ env.TARGET_BRANCH }}
submodules: 'recursive'
Expand All @@ -31,7 +31,7 @@ jobs:
git config user.name "GitHub Actions"
git config user.email [email protected]
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Setup poetry
Expand Down Expand Up @@ -63,7 +63,7 @@ jobs:
- name: Push new branch
run: git push origin ${{ env.RELEASE_BRANCH }}
- name: Create pull request into ${{ env.TARGET_BRANCH }}
uses: thomaseizinger/create-pull-request@1.0.0
uses: thomaseizinger/create-pull-request@1.3.1
with:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
head: ${{ env.RELEASE_BRANCH }}
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-private-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'recursive'
fetch-depth: 0
Expand All @@ -22,7 +22,7 @@ jobs:
git config user.name "GitHub Actions"
git config user.email [email protected]
- name: Setup Python
uses: actions/setup-python@v2
uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Setup poetry
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-public-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out sponsor repo
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: 'BC-Security/Empire-Sponsors'
submodules: 'recursive'
Expand Down Expand Up @@ -56,7 +56,7 @@ jobs:
- name: Push new branch
run: git push public ${{ env.RELEASE_BRANCH }}
- name: Create pull request into main
uses: thomaseizinger/create-pull-request@1.0.0
uses: thomaseizinger/create-pull-request@1.3.1
with:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
head: ${{ env.RELEASE_BRANCH }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-public-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'recursive'
fetch-depth: 0
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/release-sponsor-kali-start.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ jobs:
echo "TARGET_BRANCH=sponsors-main" >> $GITHUB_ENV
echo "STARKILLER_TAG=${{ github.event.inputs.starkillerVersion }}-sponsors" >> $GITHUB_ENV
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
ref: sponsors-main
submodules: 'recursive'
Expand Down Expand Up @@ -58,7 +58,7 @@ jobs:
- name: Push new branch
run: git push origin ${{ env.RELEASE_BRANCH }}
- name: Create pull request into ${{ env.TARGET_BRANCH }}
uses: thomaseizinger/create-pull-request@1.0.0
uses: thomaseizinger/create-pull-request@1.3.1
with:
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
head: ${{ env.RELEASE_BRANCH }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-sponsor-kali-tag.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ jobs:
run: |
echo "TAG_NAME=$(echo ${{ github.head_ref }} | sed 's/release\///')" >> $GITHUB_ENV
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
submodules: 'recursive'
token: ${{ secrets.RELEASE_TOKEN }}
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,6 @@
[submodule "empire/server/plugins/Report-Generation-Plugin"]
path = empire/server/plugins/Report-Generation-Plugin
url = https://github.com/BC-SECURITY/Report-Generation-Plugin.git
[submodule "empire/server/csharp/Covenant/Data/ReferenceSourceLibraries/Moriarty"]
path = empire/server/csharp/Covenant/Data/ReferenceSourceLibraries/Moriarty
url = https://github.com/BC-SECURITY/Moriarty.git
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ repos:
- id: end-of-file-fixer

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.1.9
rev: v0.2.1
hooks:
- id: ruff
args: [--fix, --exit-non-zero-on-fix]

- repo: https://github.com/psf/black-pre-commit-mirror
rev: 23.12.0
rev: 24.2.0
hooks:
- id: black
language_version: python3.10
47 changes: 46 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,47 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [5.10.1] - 2024-04-26
- Updated Starkiller to v2.8.0

### Added

- Added removal of starkiller directory to server reset (@Cx01N)

### Fixed

- Fixed missing .NET 4.5 DLLs (@Cx01N)
- Fixed run_as_user issue when dealing with directories (@Cx01N)
- Fixed missing clr package for IronPython standard library (@Cx01N)

## [5.10.0] - 2024-04-08

### Added

- Added dependabot for github actions dependencies (@Vinnybod)
- Added install option to ./ps-empire file (@Cx01N)
- Added auto pull options for submodules on startup (@Cx01N)
- Added hook and socket message to receive callback messages for individual agents (@AaronVigal)
- Added sacrificial Spawn Process bof (@Cx01N)
- Added suggested values to most modules (@Cx01N)
- Added continuous, error, and completed tasking statuses (@Cx01N)
- Added continuous and error plugin statuses (@Cx01N)
- Added Moriary module (@C01N)
- Added .NET 4.5 compile option (@C01N)

### Changed

- Updated all dependencies (@Vinnybod)
- Updated Dockerfile and install script to Python 3.12.2 (@Vinnybod)
- Updated starkiller snyc to no longer require root (@Cx01N)
- Change file permissions for empire and listener logs to be non-root (@Cx01N)

### Fixed

- Fixed issue loading `openapi.json` (@Vinnybod)
- Fixed issue when False is given for options and option is appended with 'False' (@Cx01N)
- Fixed module generation error in ComputerDetails (@Cx01N)

## [5.9.5] - 2024-02-22
- Updated Starkiller to v2.7.3

Expand Down Expand Up @@ -797,7 +838,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Updated shellcoderdi to newest version (@Cx01N)
- Added a Nim launcher (@Hubbl3)

[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.9.5...HEAD
[Unreleased]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.10.1...HEAD

[5.10.1]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.10.0...v5.10.1

[5.10.0]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.9.5...v5.10.0

[5.9.5]: https://github.com/BC-SECURITY/Empire-Sponsors/compare/v5.9.4...v5.9.5

Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
# 2) create volume storage: `docker create -v /empire --name data bcsecurity/empire`
# 3) run out container: `docker run -it --volumes-from data bcsecurity/empire /bin/bash`

FROM python:3.12.1-bullseye
FROM python:3.12.2-bullseye

LABEL maintainer="bc-security"
LABEL description="Dockerfile for Empire server and client. https://bc-security.gitbook.io/empire-wiki/quickstart/installation#docker"
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,15 @@ Empire is a post-exploitation and adversary emulation framework that is used to
- [ProcessInjection](https://github.com/3xpl01tc0d3r/ProcessInjection)
- And Many More

<!---
## Sponsors
<div align="center">

[<img src="https://github.com/BC-SECURITY/Empire/assets/9831420/f273f4b0-400c-49ce-b62f-521239a86754" width="100"/>](https://www.cybrary.it/)

[<img src="https://github.com/BC-SECURITY/Empire/assets/9831420/d14af000-80d2-4f67-b70c-b62ac42b6a52" width="100"/>](https://twitter.com/joehelle)

</div>
--->

## Release Notes

Expand All @@ -80,7 +81,7 @@ After cloning the repo, you can checkout the latest stable release by running th
git clone --recursive https://github.com/BC-SECURITY/Empire.git
cd Empire
./setup/checkout-latest-tag.sh
./setup/install.sh
./ps-empire install -y
```

If you are using the sponsors version of Empire, it will pull the sponsors version of Starkiller.
Expand Down
2 changes: 2 additions & 0 deletions docs/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,12 @@
* [Resource Files](interfaces/client/resource-files.md)
* [Starkiller](interfaces/starkiller/README.md)
* [Introduction](interfaces/starkiller/introduction.md)
* [Agent Taskings](interfaces/starkiller/agent_tasking.md)
* [Plugins](plugins/README.md)
* [Getting Started](plugins/getting-started.md)
* [Plugin Development](plugins/plugin-development.md)
* [Hooks and Filters](plugins/hooks-and-filters.md)
* [Plugin Taskings](plugins/plugin_tasking.md)
* [Bypasses](bypasses.md)
* [C#](csharp.md)
* [Module Development](module-development/README.md)
Expand Down
28 changes: 28 additions & 0 deletions docs/interfaces/starkiller/agent_tasking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Agent Taskings

Agent taskings in Empire are managed through a series of status updates that reflect the lifecycle of a task from creation to completion. These statuses help users understand the current state of tasks assigned to agents. Below are the possible statuses for agent taskings along with descriptions and representative icons.

## Queued

- **Description**: The task is queued for the agent. This status indicates that the task has been created and is waiting to be pulled by the agent.
- **Icon**: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ffa200" d="M256 0a256 256 0 1 1 0 512A256 256 0 1 1 256 0zM232 120V256c0 8 4 15.5 10.7 20l96 64c11 7.4 25.9 4.4 33.3-6.7s4.4-25.9-6.7-33.3L280 243.2V120c0-13.3-10.7-24-24-24s-24 10.7-24 24z"/></svg>

## Pulled

- **Description**: The agent has successfully pulled the tasking. This status signifies that the agent has received the task and is either processing it or about to start processing.
- **Icon**: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512" width="12" height="12"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#74C0FC" d="M400 480H48c-26.5 0-48-21.5-48-48V80c0-26.5 21.5-48 48-48h352c26.5 0 48 21.5 48 48v352c0 26.5-21.5 48-48 48zm-204.7-98.1l184-184c6.2-6.2 6.2-16.4 0-22.6l-22.6-22.6c-6.2-6.2-16.4-6.2-22.6 0L184 302.7l-70.1-70.1c-6.2-6.2-16.4-6.2-22.6 0l-22.6 22.6c-6.2 6.2-6.2 16.4 0 22.6l104 104c6.2 6.3 16.4 6.3 22.6 0z"/></svg>

## Completed

- **Description**: The task has returned data successfully. This indicates that the agent has finished executing the task and has returned the output.
- **Icon**: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#47b300" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM369 209L241 337c-9.4 9.4-24.6 9.4-33.9 0l-64-64c-9.4-9.4-9.4-24.6 0-33.9s24.6-9.4 33.9 0l47 47L335 175c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9z"/></svg>

## Error

- **Description**: If an agent reports an error for a task, it will return an ERROR status. This status allows users to identify tasks that did not execute as expected.
- **Icon**: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="12" height="12"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#ff0000" d="M256 512A256 256 0 1 0 256 0a256 256 0 1 0 0 512zM175 175c9.4-9.4 24.6-9.4 33.9 0l47 47 47-47c9.4-9.4 24.6-9.4 33.9 0s9.4 24.6 0 33.9l-47 47 47 47c9.4 9.4 9.4 24.6 0 33.9s-24.6 9.4-33.9 0l-47-47-47 47c-9.4 9.4-24.6 9.4-33.9 0s-9.4-24.6 0-33.9l47-47-47-47c-9.4-9.4-9.4-24.6 0-33.9z"/></svg>)

## Continuous

- **Description**: A special class for modules like keylogging since they are handled differently on the server due to their continuous nature. These tasks do not have a definite end and run continuously until stopped.
- **Icon**: <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 512" width="12" height="12"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path fill="#B197FC" d="M0 241.1C0 161 65 96 145.1 96c38.5 0 75.4 15.3 102.6 42.5L320 210.7l72.2-72.2C419.5 111.3 456.4 96 494.9 96C575 96 640 161 640 241.1v29.7C640 351 575 416 494.9 416c-38.5 0-75.4-15.3-102.6-42.5L320 301.3l-72.2 72.2C220.5 400.7 183.6 416 145.1 416C65 416 0 351 0 270.9V241.1zM274.7 256l-72.2-72.2c-15.2-15.2-35.9-23.8-57.4-23.8C100.3 160 64 196.3 64 241.1v29.7c0 44.8 36.3 81.1 81.1 81.1c21.5 0 42.2-8.5 57.4-23.8L274.7 256zm90.5 0l72.2 72.2c15.2 15.2 35.9 23.8 57.4 23.8c44.8 0 81.1-36.3 81.1-81.1V241.1c0-44.8-36.3-81.1-81.1-81.1c-21.5 0-42.2 8.5-57.4 23.8L365.3 256z"/></svg>
4 changes: 4 additions & 0 deletions docs/plugins/hooks-and-filters.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ This event is triggered after the tasking results are received and after they ar

This event is triggered after the agent has completed the stage2 of the checkin process, and the sysinfo has been written to the database. Its arguments are (db: Session, agent: models.Agent)

* AFTER\_AGENT\_CALLBACK\_HOOK

This event is triggered each time an agent calls back to the C2 server, after the sysinfo has been written to the database. Its arguments are (db: Session, agent_id: str)

_The number of events at the moment is very minimal. If there's an event that you would like added, open an issue on the GitHub repo, come chat in our Discord, or put up a pull request._

### Real World Examples
Expand Down
Loading
Loading