diff --git a/.github/workflows/pr.yaml b/.github/workflows/pr.yaml index db83c9d..ac37683 100644 --- a/.github/workflows/pr.yaml +++ b/.github/workflows/pr.yaml @@ -1,8 +1,6 @@ name: PR Jobs - on: pull_request: - jobs: pytest: name: Python Tests @@ -23,17 +21,15 @@ jobs: - name: Test with pytest run: | pytest - black: name: Python Style runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - - name: Run black - uses: psf/black@af0ba72a73598c76189d6dd1b21d8532255d5942 # v25 - with: - options: ". --check --verbose" - + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - name: Run black + uses: psf/black@af0ba72a73598c76189d6dd1b21d8532255d5942 # v25 + with: + options: ". --check --verbose" pylint: name: Python Lint runs-on: ubuntu-latest @@ -41,31 +37,29 @@ jobs: matrix: python-version: ["3.13"] steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - - name: Set up Python ${{ matrix.python-version }} - uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 - with: - python-version: ${{ matrix.python-version }} - - name: Install dependencies - run: | - python -m pip install --upgrade pip - pip install -r requirements/ci.txt - - name: Run pylint - run: | - pylint $(git ls-files '*.py' | grep -v dnspython) - + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@e797f83bcb11b83ae66e0230d6156d7c80228e7c # v6 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install -r requirements/ci.txt + - name: Run pylint + run: | + pylint $(git ls-files '*.py' | grep -v dnspython) eslint: name: JS Lint runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - - uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2 - - name: Setup Bun and Run ESLint - run: | - bun init -y - bun add eslint @eslint/js - bunx eslint - + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2 + - name: Setup Bun and Run ESLint + run: | + bun init -y + bun add eslint @eslint/js globals + bunx eslint stylelint: name: CSS Lint runs-on: ubuntu-latest @@ -77,16 +71,15 @@ jobs: bun init -y bun install stylelint stylelint-config-standard bunx stylelint static/css/*.css - actionlint: name: 'Github Actions YAML Lint' runs-on: ubuntu-latest steps: - - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 - - name: Download actionlint - run: | - VERSION="1.7.7" - ARCH=$(dpkg --print-architecture) - wget -c "https://github.com/rhysd/actionlint/releases/download/v${VERSION}/actionlint_${VERSION}_linux_${ARCH}.tar.gz" -O - | tar -xz - - name: Check workflow files - run: ./actionlint -shellcheck= -pyflakes= -color + - uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + - name: Download actionlint + run: | + VERSION="1.7.7" + ARCH=$(dpkg --print-architecture) + wget -c "https://github.com/rhysd/actionlint/releases/download/v${VERSION}/actionlint_${VERSION}_linux_${ARCH}.tar.gz" -O - | tar -xz + - name: Check workflow files + run: ./actionlint -shellcheck= -pyflakes= -color diff --git a/eslint.config.js b/eslint.config.js index 5dc6197..6b3cfdc 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -23,4 +23,4 @@ module.exports = defineConfig([ }] }, }, -]); \ No newline at end of file +]); diff --git a/static/js/zone.js b/static/js/zone.js index 4b4e38c..c138623 100644 --- a/static/js/zone.js +++ b/static/js/zone.js @@ -14,7 +14,7 @@ function setButtonsDisplay(row, isEditing) { function getRecordDataFromCell(dataCellList) { let returnDict = {}; dataCellList.forEach(dataCell => { - let data = ''; + let data; const input = dataCell.querySelector('input'); if (input) { data = input.value.trim(); diff --git a/zoneforge/api/records.py b/zoneforge/api/records.py index 756c99a..5de0bde 100644 --- a/zoneforge/api/records.py +++ b/zoneforge/api/records.py @@ -117,12 +117,14 @@ def post(self, zone_name: str): Creates a new DNS record in the specified zone. """ args = record_post_parser.parse_args() + ttl = args.get("ttl", None) + new_record = create_record( zone_name=zone_name, zonefile_folder=current_app.config["ZONE_FILE_FOLDER"], record_name=args["name"], record_type=args["type"], - record_ttl=args["ttl"], + record_ttl=ttl, record_data=args["data"], record_comment=args["comment"], ) diff --git a/zoneforge/core/__init__.py b/zoneforge/core/__init__.py index 96c2357..5f47151 100644 --- a/zoneforge/core/__init__.py +++ b/zoneforge/core/__init__.py @@ -1,22 +1,23 @@ import glob -import re import importlib import logging +import re from datetime import datetime from os import remove -from os.path import join, exists, basename +from os.path import basename, exists, join from typing import Type + import dns.immutable -import dns.node import dns.name -import dns.rdatatype -import dns.rdtypes.txtbase -import dns.zone +import dns.node import dns.rdata import dns.rdataset +import dns.rdatatype +import dns.rdtypes.txtbase import dns.rrset -import dns.versioned import dns.transaction +import dns.versioned +import dns.zone from werkzeug.exceptions import * # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin RECORD_FIELDS_TO_RELATIVIZE = [ @@ -91,6 +92,10 @@ def get_all_records(self, record_type: str = None, include_soa: bool = False): ] return list(all_records) + def get_default_ttl(self): + # zone.get_soa() SOA class doesnt expose TTL + return super().get_rrset(name="@", rdtype="SOA").ttl + def get_zones(zonefile_folder: str, zone_name: dns.name.Name = None) -> list[ZFZone]: zonefile_map = {} @@ -211,8 +216,8 @@ def create_record( record_name: str, record_type: str, record_data: dict, - record_ttl: int, zonefile_folder: str, + record_ttl: int = None, zone_name: dns.name.Name = None, record_class: dns.rdataclass.RdataClass = "IN", record_comment: str = None, @@ -221,6 +226,7 @@ def create_record( # perform validation only when we're writing to disk. creating a new zone requires we have the record objects first. matching_rrset = None + zone = None if write: if not zone_name: raise ValueError("A zone_name must be provided to write to a zone file.") @@ -230,6 +236,11 @@ def create_record( zone = zone[0] matching_rrset = zone.get_rrset(name=record_name, rdtype=record_type) + if record_ttl is None: + if zone is None: + raise ValueError("A zone_name must be provided to inherit TTL") + record_ttl = zone.get_default_ttl() + new_rdata = request_to_rdata( zone_name=zone_name, record_type=record_type,