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
13 changes: 2 additions & 11 deletions .github/actions/create-archive/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,9 @@ runs:
shell: bash
run: |
sudo apt install python3
- name: Create venv
- name: Create archive
shell: bash
run: |
python3 -m venv --copies venv
source venv/bin/activate
pip install -r requirements.txt
- name: Create zip
shell: bash
run: |
mkdir ConcurrentWitness2Test
cp venv *.py *.md LICENSE requirements.txt svcomp.c *.sh example ConcurrentWitness2Test/ -r
zip ConcurrentWitness2Test.zip ConcurrentWitness2Test -r
run: ./package.sh
- name: Upload results
uses: actions/upload-artifact@v4
with:
Expand Down
129 changes: 69 additions & 60 deletions .github/actions/zenodo-release/zenodo_release.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def __init__(self, token: str, record_id: str):
self.base_url = "https://zenodo.org/api"
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
"Content-Type": "application/json",
}

def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
Expand All @@ -33,7 +33,7 @@ def _make_request(self, method: str, url: str, **kwargs) -> requests.Response:
return response
except requests.exceptions.RequestException as e:
print(f"Request failed: {e}")
if hasattr(e.response, 'text'):
if hasattr(e.response, "text"):
print(f"Response: {e.response.text}")
raise

Expand All @@ -49,9 +49,9 @@ def get_draft_depositions(self) -> list:
params = {"q": f"conceptrecid:{self.record_id}", "all_versions": "true"}
response = self._make_request("GET", url, headers=self.headers, params=params)
data = response.json()

# Filter for drafts only
drafts = [d for d in data if d.get('submitted') is False]
drafts = [d for d in data if d.get("submitted") is False]
return drafts

def delete_draft(self, deposition_id: str) -> None:
Expand All @@ -68,68 +68,72 @@ def cleanup_existing_drafts(self) -> None:
"""Clean up any existing draft versions that might be in limbo."""
print("Checking for existing draft versions...")
drafts = self.get_draft_depositions()

if drafts:
print(f"Found {len(drafts)} existing draft(s). Cleaning up...")
for draft in drafts:
draft_id = draft['id']
draft_id = draft["id"]
self.delete_draft(draft_id)
else:
print("No existing drafts found.")

def create_new_version(self) -> Dict[str, Any]:
"""Create a new version of the record."""
print(f"Creating new version for record {self.record_id}")

url = f"{self.base_url}/deposit/depositions/{self.record_id}/actions/newversion"
response = self._make_request("POST", url, headers=self.headers)
data = response.json()

# Get the latest draft URL from the response
latest_draft_url = data.get('links', {}).get('latest_draft')
latest_draft_url = data.get("links", {}).get("latest_draft")
if not latest_draft_url:
raise ValueError("Could not get latest draft URL from response")

# Fetch the draft to get the actual deposition data
draft_response = self._make_request("GET", latest_draft_url, headers=self.headers)
draft_response = self._make_request(
"GET", latest_draft_url, headers=self.headers
)
draft_data = draft_response.json()

return draft_data

def update_metadata(self, deposition_data: Dict[str, Any], tool_name: str, metadata_file: Path) -> None:
def update_metadata(
self, deposition_data: Dict[str, Any], tool_name: str, metadata_file: Path
) -> None:
"""Update the metadata for the deposition."""
deposition_id = deposition_data['id']
deposition_id = deposition_data["id"]
print(f"Updating metadata for deposition {deposition_id}")

# Read the metadata template
with open(metadata_file, 'r') as f:
with open(metadata_file, "r") as f:
metadata_template = json.load(f)

# Replace placeholders
today = date.today().strftime('%Y-%m-%d')
today = date.today().strftime("%Y-%m-%d")
metadata_json = json.dumps(metadata_template)
metadata_json = metadata_json.replace('__TODAY__', today)
metadata_json = metadata_json.replace('__TOOL__', tool_name)
metadata_json = metadata_json.replace("__TODAY__", today)
metadata_json = metadata_json.replace("__TOOL__", tool_name)
metadata = json.loads(metadata_json)

# Update the deposition
url = deposition_data['links']['self']
url = deposition_data["links"]["self"]
response = self._make_request("PUT", url, headers=self.headers, json=metadata)

print(f"Metadata updated successfully (date := {today}, tool := {tool_name})")
return response.json()

def delete_existing_files(self, deposition_data: Dict[str, Any]) -> None:
"""Delete any existing files from the draft."""
files = deposition_data.get('files', [])
files = deposition_data.get("files", [])
if not files:
print("No existing files to delete.")
return

print(f"Deleting {len(files)} existing file(s)...")
for file_info in files:
file_id = file_info['id']
deposition_id = deposition_data['id']
file_id = file_info["id"]
deposition_id = deposition_data["id"]
url = f"{self.base_url}/deposit/depositions/{deposition_id}/files/{file_id}"
try:
self._make_request("DELETE", url, headers=self.headers)
Expand All @@ -139,88 +143,93 @@ def delete_existing_files(self, deposition_data: Dict[str, Any]) -> None:

def upload_file(self, deposition_data: Dict[str, Any], file_path: Path) -> None:
"""Upload a file to the deposition."""
bucket_url = deposition_data['links']['bucket']
bucket_url = deposition_data["links"]["bucket"]
filename = file_path.name

print(f"Uploading file: {filename} ({file_path.stat().st_size / (1024*1024):.2f} MB)")


print(
f"Uploading file: {filename} ({file_path.stat().st_size / (1024*1024):.2f} MB)"
)

# Upload using the bucket API (streaming)
upload_url = f"{bucket_url}/{filename}"
with open(file_path, 'rb') as f:
with open(file_path, "rb") as f:
headers = {"Authorization": f"Bearer {self.token}"}
response = self._make_request("PUT", upload_url, headers=headers, data=f)

print(f"Upload successful: {filename}")

def publish(self, deposition_data: Dict[str, Any]) -> Dict[str, Any]:
"""Publish the deposition."""
publish_url = deposition_data['links']['publish']
publish_url = deposition_data["links"]["publish"]
print(f"Publishing deposition...")

response = self._make_request("POST", publish_url, headers=self.headers)
data = response.json()
doi = data.get('doi', 'N/A')
doi_url = data.get('doi_url', 'N/A')

doi = data.get("doi", "N/A")
doi_url = data.get("doi_url", "N/A")
print(f"Publish successful!")
print(f"DOI: {doi}")
print(f"DOI URL: {doi_url}")

return data


def main():
parser = argparse.ArgumentParser(description='Create and publish a Zenodo release')
parser.add_argument('--token', required=True, help='Zenodo API token')
parser.add_argument('--record-id', required=True, help='Previous record ID')
parser.add_argument('--tool', required=True, help='Tool name')
parser.add_argument('--file', required=True, help='ZIP file to upload')
parser.add_argument('--metadata', required=True, help='Metadata JSON file')
parser.add_argument('--cleanup-drafts', action='store_true',
help='Clean up existing draft versions before creating new one')

parser = argparse.ArgumentParser(description="Create and publish a Zenodo release")
parser.add_argument("--token", required=True, help="Zenodo API token")
parser.add_argument("--record-id", required=True, help="Previous record ID")
parser.add_argument("--tool", required=True, help="Tool name")
parser.add_argument("--file", required=True, help="ZIP file to upload")
parser.add_argument("--metadata", required=True, help="Metadata JSON file")
parser.add_argument(
"--cleanup-drafts",
action="store_true",
help="Clean up existing draft versions before creating new one",
)

args = parser.parse_args()

# Validate file paths
file_path = Path(args.file)
if not file_path.exists():
print(f"Error: File not found: {file_path}")
sys.exit(1)

metadata_path = Path(args.metadata)
if not metadata_path.exists():
print(f"Error: Metadata file not found: {metadata_path}")
sys.exit(1)

try:
releaser = ZenodoReleaser(args.token, args.record_id)

# Optional: Clean up any existing drafts
if args.cleanup_drafts:
releaser.cleanup_existing_drafts()

# Create new version
deposition = releaser.create_new_version()

# Update metadata
deposition = releaser.update_metadata(deposition, args.tool, metadata_path)

# Delete any existing files from the draft
releaser.delete_existing_files(deposition)

# Upload the file
releaser.upload_file(deposition, file_path)

# Publish
releaser.publish(deposition)

print("\n=== Release completed successfully! ===")

except Exception as e:
print(f"\n=== Release failed ===")
print(f"Error: {e}")
sys.exit(1)


if __name__ == '__main__':
if __name__ == "__main__":
main()
64 changes: 64 additions & 0 deletions .github/workflows/gh-pages.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
name: Deploy www-demo to GitHub Pages
on:
push:
branches: [main]
paths:
- 'www-demo/**'
- 'witnessparser.py'
- 'witness2ast.py'
- 'tweaks.py'
- 'Exceptions.py'
- 'hacks.py'
- 'headers/**'
- 'svcomp.c'
- '.github/workflows/gh-pages.yml'
workflow_dispatch:

# Only one Pages deployment at a time; a newer push supersedes an in-flight one.
concurrency:
group: pages
cancel-in-progress: false

permissions:
contents: read

Check warning on line 23 in .github/workflows/gh-pages.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move this read permission from workflow level to job level.

See more on https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7lhFZndewo-eGlrezE&open=AZ7lhFZndewo-eGlrezE&pullRequest=11

Check notice

Code scanning / SonarCloud

Read permissions should be defined at the job level

<!--SONAR_ISSUE_KEY:AZ7lhFZndewo-eGlrezE-->Move this read permission from workflow level to job level. <p>See more on <a href="https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7lhFZndewo-eGlrezE&open=AZ7lhFZndewo-eGlrezE&pullRequest=11">SonarQube Cloud</a></p>

Check notice

Code scanning / SonarCloud

Read permissions should be defined at the job level Low

Move this read permission from workflow level to job level. See more on SonarQube Cloud
pages: write

Check notice

Code scanning / SonarCloud

Write permissions should be defined at the job level

<!--SONAR_ISSUE_KEY:AZ7lhFZndewo-eGlrezF-->Move this write permission from workflow level to job level. <p>See more on <a href="https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7lhFZndewo-eGlrezF&open=AZ7lhFZndewo-eGlrezF&pullRequest=11">SonarQube Cloud</a></p>

Check notice

Code scanning / SonarCloud

Write permissions should be defined at the job level Low

Move this write permission from workflow level to job level. See more on SonarQube Cloud
id-token: write

Check warning on line 25 in .github/workflows/gh-pages.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Move this write permission from workflow level to job level.

See more on https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7lhFZndewo-eGlrezG&open=AZ7lhFZndewo-eGlrezG&pullRequest=11

Check notice

Code scanning / SonarCloud

Write permissions should be defined at the job level

<!--SONAR_ISSUE_KEY:AZ7lhFZndewo-eGlrezG-->Move this write permission from workflow level to job level. <p>See more on <a href="https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7lhFZndewo-eGlrezG&open=AZ7lhFZndewo-eGlrezG&pullRequest=11">SonarQube Cloud</a></p>

Check notice

Code scanning / SonarCloud

Write permissions should be defined at the job level Low

Move this write permission from workflow level to job level. See more on SonarQube Cloud

jobs:
build:
runs-on: ubuntu-24.04
steps:
- name: Checkout repository
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3

# The Dockerfile is the single source of truth for assembling the
# static site (vendoring Monaco/Wasmer SDK, cloning sv-witnesses'
# linter+schemas+examples, building py.zip, etc.) -- build it here and
# extract the result rather than re-implementing those steps in YAML.
- name: Build www-demo image
run: docker build -f www-demo/Dockerfile -t cwt-demo .

- name: Extract static site from image
run: |
docker create --name cwt-demo-extract cwt-demo
mkdir -p ./pages-dist
docker cp cwt-demo-extract:/usr/share/nginx/html/. ./pages-dist/
docker rm cwt-demo-extract

- name: Upload Pages artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3
with:
path: ./pages-dist

deploy:
needs: build
runs-on: ubuntu-24.04
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- name: Configure Pages
uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b # v5
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4
7 changes: 3 additions & 4 deletions .github/workflows/sonar-check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@

- name: Install dependencies
run: |
python -m pip install --upgrade pip

Check warning on line 25 in .github/workflows/sonar-check.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Using dependencies without locking resolved versions is security-sensitive.

See more on https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7libQydewo-eGlrq8_&open=AZ7libQydewo-eGlrq8_&pullRequest=11
pip install -r requirements.txt

Check warning on line 26 in .github/workflows/sonar-check.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Using dependencies without locking resolved versions is security-sensitive.

See more on https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7libQydewo-eGlrq9B&open=AZ7libQydewo-eGlrq9B&pullRequest=11

Check warning on line 26 in .github/workflows/sonar-check.yml

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Omitting "--only-binary :all:" can lead to the execution of setup scripts. Make sure it is safe here.

See more on https://sonarcloud.io/project/issues?id=ftsrg_ConcurrentWitness2Test&issues=AZ7libQydewo-eGlrq9A&open=AZ7libQydewo-eGlrq9A&pullRequest=11

- name: SonarCloud Scan
uses: sonarsource/sonarcloud-github-action@c25d2e7e3def96d0d1781000d3c429da22cd6252 #v2.0.2
- name: SonarQube Scan
uses: SonarSource/sonarqube-scan-action@7006c4492b2e0ee0f816d36501671557c97f5995 # v8.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ venv
a.out
.idea
__pycache__
build
ConcurrentWitness2Test
ConcurrentWitness2Test.pyz
ConcurrentWitness2Test.zip
Loading
Loading