-
Notifications
You must be signed in to change notification settings - Fork 0
feat: initial website design #2
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
Changes from all commits
37f90f7
959ee2c
af8c5d4
ec5b681
1251e0c
3591eba
afa4e97
e6d1b83
97e43a2
8ce1c4b
8b0c888
70b2ea8
20b9547
5dd5df2
42b1b85
88366b2
e9b2a9d
42667fa
fe4b808
1232a3c
ed0489d
caee750
34daefb
102f1c9
26312c4
23ccabd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| name: Release Preview | ||
|
|
||
| on: | ||
| pull_request: | ||
| branches: | ||
| - main # Runs whenever a PR is opened or updated against main | ||
|
|
||
| jobs: | ||
| preview: | ||
| name: Preview Next Version | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| pull-requests: write # Required so the bot can post a comment on the PR | ||
|
|
||
| steps: | ||
| - name: Checkout Code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 # Fetch all history so git-cliff can calculate the bump correctly | ||
|
|
||
| # 1. Run git-cliff to see what version it calculates based on the PR commits | ||
| - name: Calculate Next Version | ||
| id: git_cliff_dry | ||
| uses: orhun/git-cliff-action@v4 | ||
| with: | ||
| config: cliff.toml | ||
| args: --bumped-version | ||
| continue-on-error: true | ||
|
|
||
| # 2. Extract just the version string from the output | ||
| - name: Parse Version | ||
| id: version_parse | ||
| run: | | ||
| # git-cliff outputs text; we grab the version line | ||
| VERSION=$(echo "${{ steps.git_cliff_dry.outputs.content }}" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1) | ||
| echo "calculated_version=v$VERSION" >> $GITHUB_OUTPUT | ||
|
|
||
| # 3. Post a comment on the Pull Request with the preview data | ||
| - name: Comment PR | ||
| uses: thollander/actions-comment-pull-request@v2 | ||
| with: | ||
| message: | | ||
| ### 🚀 Release Preview | ||
| If you merge this PR right now, `git-cliff` will bump the project to: | ||
| **`${{ steps.version_parse.outputs.calculated_version }}`** | ||
|
|
||
| _Based on the conventional commits found in this branch._ |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,54 @@ | ||
| name: Automated Release | ||
|
|
||
| on: | ||
| push: | ||
| branches: | ||
| - main # Triggers when code is merged into main | ||
|
|
||
| jobs: | ||
| release: | ||
| name: Generate Changelog & Release | ||
| runs-on: ubuntu-latest | ||
| permissions: | ||
| contents: write # Crucial: Allows the bot to push changes and create releases | ||
|
|
||
| steps: | ||
| - name: Checkout Code | ||
| uses: actions/checkout@v4 | ||
| with: | ||
| fetch-depth: 0 # Fetches all history so git-cliff can read past commits | ||
|
|
||
| - name: Setup Git | ||
| run: | | ||
| git config user.name "github-actions[bot]" | ||
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||
|
|
||
| # 1. Use git-cliff to calculate the next version number based on semantic commits | ||
| - name: Determine Next Version | ||
| id: next_version | ||
| uses: orhun/git-cliff-action@v4 | ||
| with: | ||
| config: cliff.toml | ||
| args: --bump --bump-deps | ||
|
|
||
| # 2. Generate the actual changelog text for this specific release | ||
| - name: Generate Changelog | ||
| id: git_cliff | ||
| uses: orhun/git-cliff-action@v4 | ||
| with: | ||
| config: cliff.toml | ||
| args: --verbose --bump --strip all | ||
| env: | ||
| OUTPUT: NEW_CHANGELOG.md | ||
|
|
||
| # 3. Create the GitHub Release and paste the changelog into it | ||
| - name: Create GitHub Release | ||
| uses: softprops/action-gh-release@v2 | ||
| with: | ||
| tag_name: ${{ steps.next_version.outputs.version }} | ||
| name: Release ${{ steps.next_version.outputs.version }} | ||
| body: ${{ steps.git_cliff.outputs.content }} | ||
| draft: false | ||
| prerelease: false | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1 +1,4 @@ | ||||||||||
| data/csedm-2019/ | ||||||||||
| **/.venv/ | ||||||||||
| **/.env | ||||||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ignore all environment-file variants, not only Line 3 only ignores the exact Suggested fix **/.env
+**/.env.*
+!**/.env.example📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| **/__pycache__/ | ||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,94 @@ | ||
| # git-cliff ~ configuration file | ||
| # https://git-cliff.org/docs/configuration | ||
|
|
||
|
|
||
| [changelog] | ||
| # A Tera template to be rendered for each release in the changelog. | ||
| # See https://keats.github.io/tera/docs/#introduction | ||
| body = """ | ||
| {% if version %}\ | ||
| ## [{{ version | trim_start_matches(pat="v") }}] - {{ timestamp | date(format="%Y-%m-%d") }} | ||
| {% else %}\ | ||
| ## [unreleased] | ||
| {% endif %}\ | ||
| {% for group, commits in commits | group_by(attribute="group") %} | ||
| ### {{ group | striptags | trim | upper_first }} | ||
| {% for commit in commits %} | ||
| - {% if commit.scope %}*({{ commit.scope }})* {% endif %}\ | ||
| {% if commit.breaking %}[**breaking**] {% endif %}\ | ||
| {{ commit.message | upper_first }}\ | ||
| {% endfor %} | ||
| {% endfor %} | ||
| """ | ||
| # Remove leading and trailing whitespaces from the changelog's body. | ||
| trim = true | ||
| # Render body even when there are no releases to process. | ||
| render_always = true | ||
| # An array of regex based postprocessors to modify the changelog. | ||
| postprocessors = [ | ||
| # Replace the placeholder <REPO> with a URL. | ||
| #{ pattern = '<REPO>', replace = "https://github.com/orhun/git-cliff" }, | ||
| ] | ||
| # render body even when there are no releases to process | ||
| # render_always = true | ||
| # output file path | ||
| # output = "test.md" | ||
|
|
||
| [git] | ||
| # Parse commits according to the conventional commits specification. | ||
| # See https://www.conventionalcommits.org | ||
| conventional_commits = true | ||
| # Exclude commits that do not match the conventional commits specification. | ||
| filter_unconventional = true | ||
| # Require all commits to be conventional. | ||
| # Takes precedence over filter_unconventional. | ||
| require_conventional = false | ||
| # Split commits on newlines, treating each line as an individual commit. | ||
| split_commits = false | ||
| # An array of regex based parsers to modify commit messages prior to further processing. | ||
| commit_preprocessors = [ | ||
| # Replace issue numbers with link templates to be updated in `changelog.postprocessors`. | ||
| #{ pattern = '\((\w+\s)?#([0-9]+)\)', replace = "([#${2}](<REPO>/issues/${2}))"}, | ||
| # Check spelling of the commit message using https://github.com/crate-ci/typos. | ||
| # If the spelling is incorrect, it will be fixed automatically. | ||
| #{ pattern = '.*', replace_command = 'typos --write-changes -' }, | ||
| ] | ||
| # Prevent commits that are breaking from being excluded by commit parsers. | ||
| protect_breaking_commits = false | ||
| # An array of regex based parsers for extracting data from the commit message. | ||
| # Assigns commits to groups. | ||
| # Optionally sets the commit's scope and can decide to exclude commits from further processing. | ||
| commit_parsers = [ | ||
| { message = "^feat", group = "<!-- 0 -->🚀 Features" }, | ||
| { message = "^fix", group = "<!-- 1 -->🐛 Bug Fixes" }, | ||
| { message = "^doc", group = "<!-- 3 -->📚 Documentation" }, | ||
| { message = "^perf", group = "<!-- 4 -->⚡ Performance" }, | ||
| { message = "^refactor", group = "<!-- 2 -->🚜 Refactor" }, | ||
| { message = "^style", group = "<!-- 5 -->🎨 Styling" }, | ||
| { message = "^test", group = "<!-- 6 -->🧪 Testing" }, | ||
| { message = "^chore\\(release\\): prepare for", skip = true }, | ||
| { message = "^chore\\(deps.*\\)", skip = true }, | ||
| { message = "^chore\\(pr\\)", skip = true }, | ||
| { message = "^chore\\(pull\\)", skip = true }, | ||
| { message = "^chore|^ci", group = "<!-- 7 -->⚙️ Miscellaneous Tasks" }, | ||
| { body = ".*security", group = "<!-- 8 -->🛡️ Security" }, | ||
| { message = "^revert", group = "<!-- 9 -->◀️ Revert" }, | ||
| { message = ".*", group = "<!-- 10 -->💼 Other" }, | ||
| ] | ||
| # Exclude commits that are not matched by any commit parser. | ||
| filter_commits = false | ||
| # Fail on a commit that is not matched by any commit parser. | ||
| fail_on_unmatched_commit = false | ||
| # An array of link parsers for extracting external references, and turning them into URLs, using regex. | ||
| link_parsers = [] | ||
| # Include only the tags that belong to the current branch. | ||
| use_branch_tags = false | ||
| # Order releases topologically instead of chronologically. | ||
| topo_order = false | ||
| # Order commits topologically instead of chronologically. | ||
| topo_order_commits = true | ||
| # Order of commits in each group/release within the changelog. | ||
| # Allowed values: newest, oldest | ||
| sort_commits = "oldest" | ||
| # Process submodules commits | ||
| recurse_submodules = false |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| JUDGE0_ENDPOINT= | ||
| JUDGE0_AUTH_KEY= |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| 3.13 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| > [!warning] | ||
| > This is currently under development | ||
|
|
||
| Hosts backend for ExemplAI. | ||
|
|
||
| # Tech stack | ||
| - FastAPI | ||
| - Python 3.13 | ||
| - uvicorn |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,82 @@ | ||
| import requests | ||
| import os | ||
| from model.student_code import StudentCode | ||
| from fastapi import FastAPI | ||
| from fastapi.middleware.cors import CORSMiddleware | ||
|
Comment on lines
+3
to
+5
|
||
| from dotenv import load_dotenv | ||
|
|
||
| # logging with rich | ||
| import logging | ||
| from rich.logging import RichHandler | ||
|
|
||
| log = logging.getLogger("rich") | ||
| log.setLevel(logging.INFO) | ||
| log.handlers.clear() | ||
| handler = RichHandler(rich_tracebacks=True) | ||
| handler.setFormatter(logging.Formatter("%(message)s", datefmt="[%X]")) | ||
| log.addHandler(handler) | ||
| log.propagate = False | ||
|
|
||
|
|
||
| # load .env file | ||
| load_dotenv() | ||
|
|
||
| app = FastAPI() | ||
|
|
||
| # Configure CORS | ||
| app.add_middleware( | ||
| CORSMiddleware, | ||
| allow_origins=["*"], # In production, replace "*" with your frontend origin (e.g., ["http://localhost:5173"]) | ||
| allow_credentials=True, | ||
| allow_methods=["*"], # Allows all methods, including POST and OPTIONS | ||
| allow_headers=["*"], # Allows all headers | ||
| ) | ||
|
Comment on lines
+26
to
+33
|
||
|
|
||
|
|
||
|
|
||
| @app.get("/") | ||
| def read_root(): | ||
| return {"Hello": "World"} | ||
|
|
||
|
|
||
| # send to url | ||
| # todo: prob need question id to do this, testing | ||
| # code execution for now | ||
| @app.post('/execute') | ||
| def judge0_execution(student_code: StudentCode): | ||
| # print student code | ||
|
|
||
| # send the code to judge0 | ||
| # make new request to configured judge0 endpoint - current would block until done | ||
| exec_url = os.getenv('JUDGE0_ENDPOINT') + '/submissions?base64_encoded=false&wait=true' | ||
|
|
||
|
Comment on lines
+49
to
+52
|
||
| # beautifully format the request payload | ||
| payload = { | ||
| 'source_code': student_code.code, | ||
| 'language_id': 71, # python | ||
| } | ||
|
|
||
| # setup headers if auth key is provided | ||
| headers = {} | ||
| auth_key = os.getenv('JUDGE0_AUTH_KEY') | ||
| if auth_key: | ||
| headers['X-Auth-Token'] = auth_key | ||
|
|
||
| # make request | ||
| response = requests.post(exec_url, json=payload, headers=headers) | ||
|
|
||
| # get the output | ||
| output = response.json() | ||
|
|
||
|
Comment on lines
+65
to
+70
|
||
| # print the output using rich | ||
| log.info(output) | ||
|
|
||
| # return the output | ||
| return output | ||
|
Comment on lines
+45
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Missing timeout, error handling, and env validation on Judge0 proxy. Several issues in this endpoint:
🛠️ Proposed fix+from fastapi import FastAPI, HTTPException
+
+JUDGE0_ENDPOINT = os.getenv('JUDGE0_ENDPOINT')
+if not JUDGE0_ENDPOINT:
+ raise RuntimeError("JUDGE0_ENDPOINT environment variable is required")
+
`@app.post`('/execute')
def judge0_execution(student_code: StudentCode):
- exec_url = os.getenv('JUDGE0_ENDPOINT') + '/submissions?base64_encoded=false&wait=true'
+ exec_url = JUDGE0_ENDPOINT + '/submissions?base64_encoded=false&wait=true'
payload = {
'source_code': student_code.code,
'language_id': 71,
}
headers = {}
auth_key = os.getenv('JUDGE0_AUTH_KEY')
if auth_key:
headers['X-Auth-Token'] = auth_key
- response = requests.post(exec_url, json=payload, headers=headers)
-
- output = response.json()
+ try:
+ response = requests.post(exec_url, json=payload, headers=headers, timeout=30)
+ response.raise_for_status()
+ output = response.json()
+ except requests.exceptions.Timeout:
+ raise HTTPException(status_code=504, detail="Judge0 request timed out")
+ except requests.exceptions.RequestException as e:
+ log.error(f"Judge0 request failed: {e}")
+ raise HTTPException(status_code=502, detail="Failed to reach code execution service")
+ except ValueError:
+ raise HTTPException(status_code=502, detail="Invalid response from code execution service")
log.info(output)
return output🧰 Tools🪛 ast-grep (0.43.0)[info] 65-65: no timeout was given on call to external resource (requests-timeout) 🪛 Ruff (0.15.17)[error] 66-66: Probable use of (S113) 🤖 Prompt for AI AgentsSource: Linters/SAST tools |
||
|
|
||
|
|
||
|
|
||
|
|
||
| @app.get("/items/{item_id}") | ||
| def read_item(item_id: int, q: str | None = None): | ||
| return {"item_id": item_id, "q": q} | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| from pydantic import BaseModel | ||
|
|
||
| class StudentCode(BaseModel): | ||
| code: str | ||
|
|
||
|
|
||
| # data model for sending to judge0 | ||
| class CodeSubmission(StudentCode): | ||
| language_id: int | ||
| source_code: str | ||
|
|
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,12 @@ | ||
| [project] | ||
| name = "server" | ||
| version = "0.1.0" | ||
| description = "Add your description here" | ||
| readme = "README.md" | ||
| requires-python = ">=3.13" | ||
| dependencies = [ | ||
| "fastapi[standard]>=0.136.3", | ||
| "python-dotenv>=1.2.2", | ||
| "requests>=2.34.2", | ||
| "rich>=15.0.0", | ||
| ] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: RMIT-BDSL/ExemplAI
Length of output: 471
🏁 Script executed:
Repository: RMIT-BDSL/ExemplAI
Length of output: 2117
Pin action SHAs and disable checkout credential persistence.
Lines 17, 29, 37, and 46 use mutable action tags (
@v4,@v2), and line 19 omitspersist-credentials: false. In a release workflow withcontents: writepermission, this creates a supply-chain attack surface and increases the blast radius of a potential token compromise.Suggested hardening diff
🧰 Tools
🪛 zizmor (1.25.2)
[warning] 16-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[error] 17-17: unpinned action reference (unpinned-uses): action is not pinned to a hash (required by blanket policy)
(unpinned-uses)
🤖 Prompt for AI Agents
Source: Linters/SAST tools