diff --git a/.gitignore b/.gitignore
index 080f7c867..0b9486fbb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -26,8 +26,5 @@ doc/build
 # release notes build
 releasenotes/build
 
-# upper-constraints handling for image builds
-upper-constraints.txt
-
 # auto-generated example file
 etc/ironic_python_agent/ironic_python_agent.conf.sample
diff --git a/tox.ini b/tox.ini
index 5a9a83f79..13b44ab64 100644
--- a/tox.ini
+++ b/tox.ini
@@ -12,6 +12,7 @@ setenv =
   OS_LOG_CAPTURE={env:OS_LOG_CAPTURE:true}
   LANGUAGE=en_US
   LC_ALL=en_US.utf-8
+  TOX_CONSTRAINTS_FILE=upper-constraints.txt
 deps =
   -c{env:TOX_CONSTRAINTS_FILE:https://releases.openstack.org/constraints/upper/master}
   -r{toxinidir}/requirements.txt
diff --git a/upper-constraints.txt b/upper-constraints.txt
new file mode 100644
index 000000000..714cebeb2
--- /dev/null
+++ b/upper-constraints.txt
@@ -0,0 +1,601 @@
+voluptuous===0.15.2
+chardet===5.2.0
+enum-compat===0.0.3
+rsa===4.9
+restructuredtext-lint===1.4.0
+netmiko===4.5.0
+sshtunnel===0.4.0
+PasteDeploy===3.1.0
+typing===3.7.4.3
+Routes===2.5.1
+rtslib-fb===2.1.76
+oslo.limit===2.6.0
+yarl===1.18.3
+tzdata===2025.1
+smmap===5.0.2
+confget===5.1.2
+XStatic-Angular-Bootstrap===2.5.0.0
+WebOb===1.8.9
+sphinxcontrib-actdiag===3.0.0
+pecan===1.5.1
+os-api-ref===3.0.1
+python-ldap===3.4.4
+oslo.concurrency===7.0.0
+websocket-client===1.8.0
+osprofiler===4.2.0
+os-resource-classes===1.1.0
+tabulate===0.9.0
+python-ironic-inspector-client===5.2.0
+lxml===5.3.0
+vintage===0.4.1
+rst2txt===1.1.0
+setproctitle===1.3.4
+pytest===8.1.2
+python-slugify===8.0.4
+cursive===0.2.3
+oslo.service===4.0.0
+django-appconf===1.0.6
+ntc_templates===7.6.0
+sphinxcontrib-nwdiag===2.0.0
+rbd-iscsi-client===0.1.8
+requests-aws===0.1.8
+alabaster===0.7.16;python_version=='3.9'
+alabaster===1.0.0;python_version>='3.10'
+multidict===6.1.0
+pbr===6.1.1
+munch===4.0.0
+waiting===1.5.0
+attrs===24.3.0
+microversion-parse===2.0.0
+jwcrypto===1.5.6
+Pint===0.23;python_version=='3.9'
+Pint===0.24.4;python_version>='3.10'
+oslo.i18n===6.5.0
+jsonpath-rw-ext===1.2.2
+python-mistralclient===5.3.0
+oslo.context===5.7.0
+rcssmin===1.1.2
+pycadf===4.0.1
+grpcio===1.70.0
+sniffio===1.3.1
+fixtures===4.2.2
+neutron-lib===3.18.0
+XStatic-FileSaver===1.3.2.0
+jaraco.functools===4.1.0
+jaraco.text===4.0.0
+oslo.metrics===0.10.1
+storage-interfaces===1.0.5
+persist-queue===1.0.0
+pystache===0.6.7
+XStatic-Font-Awesome===4.7.0.0
+nose===1.3.7
+aiohttp===3.11.11
+waitress===3.0.2
+os-refresh-config===14.0.0
+pysnmp===7.1.16
+Mako===1.3.8
+pyScss===1.4.0
+sphinxcontrib-htmlhelp===2.1.0
+XStatic-jQuery===3.5.1.1
+jaraco.collections===5.1.0
+ddt===1.7.2
+XStatic-Graphlib===2.1.7.0
+pyserial===3.5
+moto===5.0.27
+infi.dtypes.wwn===0.1.1
+rpm-vercmp===0.1.2
+python-freezerclient===5.2.0
+python-vitrageclient===5.2.0
+py-pure-client===1.61.0
+krest===1.3.6
+psycopg2===2.9.10
+networkx===3.2.1;python_version=='3.9'
+networkx===3.4.2;python_version>='3.10'
+cheroot===10.0.1
+XStatic-Angular===1.8.2.2
+types-requests===2.31.0.6
+zuul-sphinx===0.7.0
+ply===3.11
+google-api-core===2.24.0
+requests-toolbelt===1.0.0
+simplejson===3.19.3
+types-paramiko===3.5.0.20240928
+immutables===0.21
+python-swiftclient===4.6.0
+pyOpenSSL===25.0.0
+monasca-common===3.8.0
+zeroconf===0.141.0
+scipy===1.13.1;python_version=='3.9'
+scipy===1.15.1;python_version>='3.10'
+opentelemetry-exporter-otlp===1.29.0
+python-gnupg===0.5.4
+mypy-extensions===1.0.0
+rsd-lib===1.2.0
+XStatic-Jasmine===2.4.1.2
+googleapis-common-protos===1.66.0
+python-glanceclient===4.7.0
+prometheus_client===0.21.1
+jaraco.classes===3.4.0
+debtcollector===3.0.0
+responses===0.25.6
+croniter===6.0.0
+horizon===25.1.0
+octavia-lib===3.7.0
+python-watcherclient===4.7.0
+MarkupSafe===3.0.2
+types-python-dateutil===2.9.0.20241206
+ruamel.yaml.clib===0.2.12
+doc8===1.1.2
+pymongo===4.10.1
+python-cloudkittyclient===5.3.0
+soupsieve===2.6
+sqlparse===0.5.3
+oslotest===5.0.0
+jsonpointer===3.0.0
+defusedxml===0.7.1
+opentelemetry-sdk===1.29.0
+netaddr===1.3.0
+pyghmi===1.5.72
+autocommand===2.2.2
+sphinxcontrib-blockdiag===3.0.0
+aiosqlite===0.20.0
+thrift===0.21.0
+gnocchiclient===7.1.0
+wcwidth===0.2.13
+sphinxcontrib.datatemplates===0.11.0
+jsonpath-rw===1.4.0
+prettytable===3.13.0
+vine===5.1.0
+taskflow===5.10.0
+arrow===1.3.0
+semantic-version===2.10.0
+async-timeout===5.0.1;python_version=='3.10'
+async-timeout===5.0.1;python_version=='3.9'
+virtualbmc===3.1.0
+SQLAlchemy===2.0.37
+pyroute2===0.8.1
+google-auth===2.38.0
+kazoo===2.10.0
+pyspnego===0.11.2
+XStatic-roboto-fontface===0.5.0.0
+pyudev===0.24.3
+eventlet===0.39.0
+openstack-doc-tools===4.0.0
+oslo.messaging===16.0.0
+jira===3.8.0
+extras===1.0.0
+PyJWT===2.10.1
+typing_extensions===4.12.2
+XStatic-lodash===4.16.4.2
+zVMCloudConnector===1.6.3
+paramiko===3.5.0
+ifaddr===0.2.0
+reno===4.1.0
+ncclient===0.6.16
+imagesize===1.4.1
+pydot===3.0.4
+urllib3===1.26.20
+graphviz===0.20.3
+portend===3.2.0
+PyKMIP===0.10.0
+python-observabilityclient===0.3.0
+whereto===0.4.0
+pywbem===1.7.2
+python-subunit===1.4.4
+tornado===6.4.2
+pycparser===2.22
+mock===5.1.0
+PyYAML===6.0.2
+beautifulsoup4===4.12.3
+ovs===3.4.1
+cryptography===44.0.0
+httpcore===1.0.7
+URLObject===2.4.3
+psycopg2-binary===2.9.10
+openstack-release-test===8.0.0
+pycryptodomex===3.21.0
+requests-mock===1.12.1
+os-apply-config===14.0.0
+oslosphinx===4.18.0
+gunicorn===23.0.0
+storpool===7.3.0
+textfsm===1.1.3
+python-3parclient===4.2.14
+django-compressor===4.5.1
+libvirt-python===11.0.0
+python-zunclient===5.2.0
+tzlocal===5.2
+sphinxcontrib-jsmath===1.0.1
+python-novaclient===18.8.0
+pact===1.12.0
+bcrypt===4.0.1
+exceptiongroup===1.2.2;python_version=='3.10'
+exceptiongroup===1.2.2;python_version=='3.9'
+os-client-config===2.1.0
+XStatic-Angular-Gettext===2.4.1.0
+Deprecated===1.2.17
+h11===0.14.0
+Pygments===2.19.1
+XStatic-Hogan===2.0.0.3
+XStatic-objectpath===1.2.1.0
+python-manilaclient===5.2.0
+sphinxcontrib-serializinghtml===2.0.0
+requests===2.32.3
+snowballstemmer===2.2.0
+Jinja2===3.1.5
+XStatic-Bootstrap-SCSS===3.4.1.0
+pyzabbix===1.3.1
+ptyprocess===0.7.0
+threadloop===1.0.2
+amqp===5.3.1
+ruamel.yaml===0.18.10
+websockify===0.12.0
+CherryPy===18.10.0
+gssapi===1.9.0
+XStatic-JQuery.quicksearch===2.0.3.2
+pyasn1_modules===0.4.1
+mpmath===1.3.0
+python-binary-memcached===0.31.4
+jaraco.context===6.0.1
+django-debreach===2.1.0
+sphinx-feature-classification===2.0.0
+XStatic-JQuery-Migrate===3.3.2.1
+pytest-html===4.1.1
+appdirs===1.4.4
+google-auth-httplib2===0.2.0
+daiquiri===3.2.5.1;python_version=='3.9'
+daiquiri===3.3.0;python_version>='3.10'
+influxdb===5.3.2
+funcparserlib===2.0.0a0
+passlib===1.7.4
+cliff===4.8.0
+os-brick===6.10.0
+scp===0.15.0
+python-zaqarclient===2.10.0
+ldappool===3.0.0
+joblib===1.4.2
+google-api-python-client===2.159.0
+castellan===5.2.0
+oslo.versionedobjects===3.5.0
+enmerkar===0.7.1
+webcolors===24.11.1
+aodhclient===3.7.0
+autobahn===24.4.2
+SQLAlchemy-Utils===0.41.2
+retryz===0.1.9
+pluggy===1.5.0
+coverage===7.6.10
+freezegun===1.5.1
+mdurl===0.1.2
+toml===0.10.2
+pycdlib===1.14.0
+pyperclip===1.9.0
+cassandra-driver===3.29.2
+XStatic-Angular-Schema-Form===0.8.13.0
+opentelemetry-exporter-otlp-proto-http===1.29.0
+gabbi===3.1.0
+nwdiag===3.0.0
+XStatic-bootswatch===3.3.7.0
+pytest-xdist===3.6.1
+XStatic-JS-Yaml===3.8.1.0
+XStatic-term.js===0.0.7.0
+oslo.log===7.0.0
+nodeenv===1.9.1
+gossip===2.4.0
+suds-community===1.2.0
+oslo.middleware===6.3.0
+XStatic-mdi===1.6.50.2
+django-pyscss===2.0.3
+uritemplate===4.1.1
+docutils===0.21.2
+threadpoolctl===3.5.0
+os-ken===2.11.2
+ujson===5.10.0
+selenium===3.141.0
+mistral-lib===3.2.0
+dogtag-pki===11.2.1
+XStatic-Angular-UUID===0.0.4.0
+purestorage===1.19.0
+sphinxcontrib-seqdiag===3.0.0
+os-win===5.9.0
+capacity===1.3.14
+markdown-it-py===3.0.0
+retrying===1.3.4
+XStatic-Dagre===0.6.4.1
+platformdirs===4.3.6
+pydotplus===2.0.2
+boto3===1.36.6
+jeepney===0.8.0
+stestr===4.1.0
+pillow===11.1.0
+infoblox-client===0.6.1
+pysmi-lextudio===1.4.3
+oslo.serialization===5.6.0
+warlock===2.0.1
+exabgp===4.2.22
+aiomysql===0.2.0
+types-simplejson===3.19.0.20241221
+sphinxcontrib-httpdomain===1.8.1
+metalsmith===2.4.0
+s3transfer===0.11.2
+text-unidecode===1.3
+sphinxcontrib-svg2pdfconverter===1.2.3
+oslo.vmware===4.5.0
+XStatic-moment===2.8.4.3
+autopage===0.5.2
+gitdb===4.0.12
+python-monascaclient===2.8.0
+ldap3===2.9.1
+opentelemetry-api===1.29.0
+frozenlist===1.5.0
+automaton===3.2.0
+types-urllib3===1.26.25.14
+os-service-types===1.7.0
+keyring===25.6.0
+elementpath===4.7.0
+wsgi_intercept===1.13.1
+jsonschema-specifications===2024.10.1
+testscenarios===0.5.0
+sphinxcontrib-pecanwsme===0.11.0
+sadisplay===0.4.9
+infinisdk===258.0.0
+packaging===24.2
+opentelemetry-exporter-otlp-proto-grpc===1.29.0
+XStatic-Dagre-D3===0.4.17.0
+psutil===6.1.1
+txaio===23.1.1
+elasticsearch===2.4.1
+django-nose===1.4.7
+asgiref===3.8.1
+XStatic-JQuery.TableSorter===2.14.5.2
+pifpaf===3.2.3
+blockdiag===3.0.0
+testtools===2.7.2
+infi.dtypes.iqn===0.4.0
+XStatic-tv4===1.2.7.0
+XStatic-JSEncrypt===2.3.1.1
+python-cinderclient===9.6.0
+keystonemiddleware===10.8.0
+django-formtools===2.5.1
+XStatic-Spin===1.2.5.3
+rich===13.9.4
+tap-as-a-service===14.0.0
+os-traits===3.3.0
+typepy===1.3.4
+SecretStorage===3.3.3
+opentracing===2.4.0
+XStatic-Rickshaw===1.5.1.0
+iso8601===2.1.0
+tooz===6.3.0
+idna===3.10
+yamlloader===1.5.1
+protobuf===5.29.3
+sushy===5.4.0
+python-neutronclient===11.4.0
+types-setuptools===75.8.0.20250110
+pika===1.3.2
+oslo.cache===3.9.0
+WebTest===3.0.3
+os-collect-config===14.0.0
+edgegrid-python===2.0.0
+python-octaviaclient===3.9.0
+pysaml2===7.5.0
+requests-oauthlib===2.0.0
+oslo.reports===3.5.0
+pysnmp-lextudio===5.0.33
+bitmath===1.3.3.1
+ceilometermiddleware===3.6.0
+testrepository===0.0.21
+sympy===1.13.3
+Logbook===1.8.0
+PyNaCl===1.5.0
+osc-lib===3.2.0
+python-consul===1.1.0
+more-itertools===10.6.0
+seqdiag===3.0.0
+zc.lockfile===3.0.post1
+numpy===2.0.0;python_version=='3.9'
+numpy===2.2.2;python_version>='3.10'
+msgpack===1.1.0
+Sphinx===7.4.7;python_version=='3.9'
+Sphinx===8.1.3;python_version>='3.10'
+oslo.config===9.7.0
+openstackdocstheme===3.4.1
+osc-placement===4.5.0
+rpds-py===0.22.3
+zake===0.2.2
+flux===1.3.5
+pysnmpcrypto===0.0.4
+flexparser===0.4
+krb5===0.7.0
+PyMySQL===1.1.1
+uhashring===2.3
+kubernetes===32.0.0
+httplib2===0.22.0
+betamax===0.9.0
+construct===2.10.70
+pytest-metadata===3.1.1
+pyparsing===3.2.1
+geomet===0.2.1.post1
+opentelemetry-exporter-otlp-proto-common===1.29.0
+distlib===0.3.9
+XStatic-Moment-Timezone===0.5.22.0
+dogpile.cache===1.3.3
+python-barbicanclient===7.0.0
+salt===3007.1
+opentelemetry-semantic-conventions===0.50b0
+api-object-schema===2.0.0
+blinker===1.9.0
+WSME===0.12.1
+tomli===2.2.1;python_version=='3.10'
+tomli===2.2.1;python_version=='3.9'
+oslo.upgradecheck===2.4.0
+sherlock===0.4.1
+tempora===5.8.0
+stevedore===5.4.0
+pywinrm===0.5.0
+botocore===1.36.6
+xmltodict===0.14.2
+pyasn1===0.6.0
+oslo.rootwrap===7.4.0
+Django===4.2.18
+pexpect===4.9.0
+contextvars===2.4
+cmd2===2.5.9
+python-json-logger===3.2.1
+redis===5.2.1
+jmespath===1.0.1
+click===8.1.8
+XStatic-smart-table===1.4.13.2
+kuryr-lib===3.1.0
+scrypt===0.8.27
+jsonpatch===1.33
+libsass===0.23.0
+os-testr===3.0.0
+cotyledon===1.7.3
+xattr===1.1.4
+systemd-python===235
+python-memcached===1.62
+openstacksdk===4.3.0
+infi.dtypes.nqn===0.1.0
+looseversion===1.3.0
+six===1.17.0
+dulwich===0.22.7
+dfs-sdk===1.2.27
+sentinels===1.0.0
+kombu===5.4.2
+distro===1.9.0
+zstd===1.5.6.2
+yaql===3.0.0
+durationpy===0.9
+requestsexceptions===1.4.0
+testresources===2.0.1
+falcon===4.0.2
+tomlkit===0.13.2
+etcd3gw===2.4.2
+timelib===0.3.0
+Flask-RESTful===0.3.10
+GitPython===3.1.44
+requests_ntlm===1.3.0
+python-ironicclient===5.10.0
+babel===2.16.0
+XStatic===1.0.3
+XStatic-Angular-FileUpload===12.2.13.0
+python-openstackclient===7.2.1
+pyzmq===26.2.0
+oslo.db===17.1.0
+simplegeneric===0.8.1
+python-pcre===0.7
+yappi===1.6.10
+mbstrdecoder===1.1.4
+pymemcache===4.0.0
+wrapt===1.17.2
+oslo.privsep===3.5.0
+sphinxcontrib-apidoc===0.5.0
+oslo.policy===4.5.0
+hvac===2.3.0
+pyeclib===1.6.4
+ndg-httpsclient===0.5.1
+repoze.lru===0.7
+rfc3986===2.0.0
+tenacity===9.0.0
+python-designateclient===6.1.0
+future===1.0.0
+pytest-cov===4.1.0
+reactivex===4.0.4
+Paste===3.10.1
+pytest-django===4.9.0
+jaeger-client===4.8.0
+XStatic-Json2yaml===0.1.1.0
+boto===2.49.0
+os-vif===4.0.0
+hyperlink===21.0.0
+mitba===1.1.1
+python-masakariclient===8.5.0
+Werkzeug===3.1.3
+APScheduler===3.11.0
+xmlschema===2.5.1
+python-troveclient===8.7.0
+cachez===0.1.2
+XStatic-Bootstrap-Datepicker===1.4.0.0
+netifaces===0.11.0
+propcache===0.2.1
+cachetools===5.5.1
+flexcache===0.3
+sphinxcontrib-qthelp===2.0.0
+keystoneauth1===5.9.1
+statsd===4.0.1
+proto-plus===1.25.0
+python-keystoneclient===5.5.0
+ceilometer===23.0.0
+diskimage-builder===3.37.0
+heat-translator===3.1.0
+python-magnumclient===4.7.0
+docker===7.1.0
+storops===1.2.11
+anyio===4.8.0
+aiosignal===1.3.2
+XStatic-Angular-lrdragndrop===1.0.2.6
+ovsdbapp===2.10.0
+aniso8601===10.0.0
+rjsmin===1.2.2
+icalendar===6.1.1
+decorator===5.1.1
+DateTimeRange===2.3.1
+cffi===1.17.1
+python-cyborgclient===2.4.0
+futurist===3.0.0
+jsonschema===4.23.0
+sphinxcontrib-devhelp===2.0.0
+python-blazarclient===4.2.0
+alembic===1.14.1
+execnet===2.1.1
+glance-store===4.9.0
+sphinxcontrib-programoutput===0.18
+storpool.spopenstack===3.2.0
+dnspython===2.7.0
+oauthlib===3.2.2
+logutils===0.3.5
+zipp===3.21.0
+greenlet===3.1.1
+XStatic-Angular-Vis===4.16.0.0
+iniconfig===2.0.0
+referencing===0.36.1
+confluent-kafka===2.8.0
+backports.tarfile===1.2.0
+xvfbwrapper===0.2.9
+influxdb-client===1.48.0
+tosca-parser===2.12.0
+python-consul2===0.1.5
+charset-normalizer===3.4.1
+Flask===3.1.0
+httpx===0.28.1
+sqlalchemy-filters===0.13.0
+sphinxcontrib-runcmd===0.2.0
+confspirator===0.3.0
+fasteners===0.19
+importlib-metadata===6.2.1;python_version=='3.9'
+importlib-metadata===8.5.0;python_version>='3.10'
+sortedcontainers===2.4.0
+python-linstor===1.24.0
+filelock===3.17.0
+python-tackerclient===2.3.0
+python-heatclient===4.1.0
+oslo.utils===8.0.0
+requests-kerberos===0.15.0
+itsdangerous===2.2.0
+XStatic-jquery-ui===1.13.0.1
+monasca-statsd===2.7.0
+python-dateutil===2.9.0.post0
+virtualenv===20.29.1
+colorama===0.4.6
+confetti===2.5.3
+ironic-lib===7.0.0
+aiohappyeyeballs===2.4.4
+pytz===2024.2
+opentelemetry-proto===1.29.0
+XStatic-D3===3.5.17.0
+actdiag===3.0.0
+sysv-ipc===1.1.0
+sphinxcontrib-applehelp===2.0.0
+scikit-learn===1.6.1