<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/"><channel><atom:link href="https://www.finalbuilder.com/DesktopModules/LiveBlog/API/Syndication/GetRssFeeds?Category=delphi&amp;mid=632&amp;PortalId=0&amp;tid=181&amp;ItemCount=20" rel="self" type="application/rss+xml" /><title>VSoft Technologies Blogs</title><description>VSoft Technologies Blogs - posts about our products and software development.</description><link>https://www.finalbuilder.com/resources/blogs</link><item><title>DPM Package Manager for Delphi - Beta</title><link>https://www.finalbuilder.com/resources/blogs/postid/884/dpm-package-manager-for-delphi-beta</link><category>Delphi,DPM,FinalBuilder,Signotaur</category><pubDate>Mon, 01 Jun 2026 08:14:18 GMT</pubDate><description>&lt;p&gt;I've been working on a package manager for Delphi for a long time. I hit a roadblock and life got in the way and I couldn't find the time (or the motivation if I am honest) to work on it. I was using it every day, but it wasn't really usable for the masses. That was until recently..&lt;/p&gt;

&lt;h2&gt;Design time packages&lt;/h2&gt;

&lt;p&gt;That roadblock I hit was loading design time packages (bpl's). The early design decision to create separate dpm package files per compilerversion/platform made it really difficult to control which design time packages to load/unload and to get the order correct - failing to do so resulted in an unstable IDE at best.&lt;/p&gt;

&lt;p&gt;Late last year I started on a redesign, using a single package file per compiler version. This simplified the design time bpl install story considerably. I've been chipping away at this redesign for a while now, adding a bunch of features along the way and completely rewriting the package server.&lt;/p&gt;

&lt;p&gt;Note that this version is incompatible with the previously published Alpha releases - hopefully there will not be any more breaking changes.&lt;/p&gt;

&lt;h2 id="what-works"&gt;What works&lt;/h2&gt;

&lt;p&gt;DPM is pretty much feature complete (for an initial release)&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;Creating packages (library authors)&lt;/li&gt;
	&lt;li&gt;Pushing packages to a package repository (directory or server)&lt;/li&gt;
	&lt;li&gt;Public package repository&lt;/li&gt;
	&lt;li&gt;Installing and Restoring packages, including dependencies and design time components.&lt;/li&gt;
	&lt;li&gt;Multiple package sources&lt;/li&gt;
	&lt;li&gt;Package Signing - both Author (code signing certificate) and Repository signing (automatic during upload).&lt;/li&gt;
	&lt;li&gt;Repository and Author Trust. You can decide which authors and repositories to trust.&lt;/li&gt;
	&lt;li&gt;SBOM generation - both CycloneDX and SPDX output formats.&lt;/li&gt;
	&lt;li&gt;Vulerability scanning via SBOM and osv.dev&lt;/li&gt;
	&lt;li&gt;CLI and IDE plugin.&lt;/li&gt;
	&lt;li&gt;Extensive documentation (still a work in progress but there is a lot there).&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Supported Delphi Versions&lt;/h2&gt;

&lt;p&gt;Delphi XE2 to 13.1&lt;/p&gt;

&lt;p&gt;I decided a long time ago that I wanted to support as many Delphi versions as possible - the idea being that DPM might make it easier for users to upgrade eventually. It's not easy - I'm constantly writing code that works on one version and doesn't on another. If DPM were just a CLI tool or a standalone UI tool, we could of course go back much further, but since the CLI and the IDE plugins share the core code, supporting versions earlier than XE2 became too difficult - either a lack of generics or generics bugs (of which there were plenty in early versions). My view is that those who are still using Delphi 7 are never going to upgrade, they are already happy with their lot and no likely to use DPM anyway!&lt;/p&gt;

&lt;h2&gt;What about C++ Builder and FPC/Lazarus&lt;/h2&gt;

&lt;p&gt;I would love to see support for both C++Builder and Lazarus - but simply do not have the time or expertise to tackle them myself - open to contributions - see &lt;a href="https://docs.delphi.dev/contributing.html" target="_blank"&gt;Contributing&lt;/a&gt; before making a start on it!&lt;/p&gt;

&lt;h2&gt;How do I use it?&lt;/h2&gt;

&lt;p&gt;Download and install the client from github - The installer allows you to install for the current user, or for all users (requires elevation to install). It installs both the CLI and the IDE plugins for the versions of RAD Studio you have installed.&lt;/p&gt;

&lt;p&gt;Once a project is loaded in the IDE, you can access the DPM editor view via the Project tree (right click on a project or project group, Manage DPM Packages), or via the Project menu. There is also a toolbar button you can add to your toolbar.&lt;/p&gt;

&lt;p style="text-align: center;"&gt;&lt;img alt="The DPM IDE plugin loaded showing the installed packages" src="https://cdn.finalbuilder.com/blog/vincent/dpm-beta/ide-plugin.png" /&gt;&lt;/p&gt;

&lt;p&gt;The DPM editor view presents a list of available packages, click on one to highlight it, then at the top right you can click on the [+] button to install the package. You can choose the version to install, and whether to install it for all projects in the group, or just specific projects. DPM will download the package and any of it's dependent packages, build them (in the correct order) and add them to your project's Search Path - ready to use. If the package has any design time components, those are loaded into the IDE at the same time. The next time you open the project, the DPM Restore process will run, ensuring that any referenced packages are installed, if any are missing (like for example when you open the project on another machine) - it will automatically download and install them.&lt;/p&gt;

&lt;p&gt;You can filter, search the package list to find packages you want (of course there are not many packages available yet) - by default pre-release packages are not shown, check on the pre-release option to show them.&lt;/p&gt;

&lt;p&gt;When newer versions of packages become available, you can upgrade them in the IDE - the upgrade button will show when you select a package with an upgrade available.&lt;/p&gt;

&lt;h2&gt;New Features&lt;/h2&gt;

&lt;p&gt;As part of this overhaul, we added a few new features&lt;/p&gt;

&lt;h3&gt;Package Signing&lt;/h3&gt;

&lt;p&gt;Package signing provides a mechanism for ensure package Integrity, Authenticity and Provenance.&lt;/p&gt;

&lt;p&gt;Package authors can (optionally) sign their packages with a Code Signing Certificate, by using the `dpm sign` command after packing - using a pfx file (although those are rare these days), using a usb token (will prompt for pin/password) or using Signotaur (with v2 coming soon) or Azure Key Vault (untested at this stage).&lt;/p&gt;

&lt;p&gt;The public package repository also signs the package when it is uploaded, if an Author Signature is present then it is referenced by Repository Signature that is added to the package.&lt;/p&gt;

&lt;p&gt;If some opens the package locally (it's a zip file) and adds or removes files, then that will invalidate the signature(s). If someone removes the signatures - then that package's authenticity, integrity and provenance is no longer assured.&lt;/p&gt;

&lt;h3&gt;Author and Repository Trust&lt;/h3&gt;

&lt;p&gt;On the client side, you can add Authors and Repositories to a trust list. By default the public repository is trusted.&lt;/p&gt;

&lt;h3&gt;Signature Downgrade Protection&lt;/h3&gt;

&lt;p&gt;DPM remembers whether a package was previously signed. If a later version of the same package shows up unsigned, that is suspicious - either an attacker is trying to substitute a malicious package, or the publisher has lost their signing key. The default setting on the client for this is prompt - the user will be prompted to continue installing the package.&lt;/p&gt;

&lt;p&gt;The package server also adds signing downgrade protection. If the author uploads an unsigned package that was previously signed in earlier versions, that upload will fail. The author can of course acknowledge the downgrade on the server and re-upload the package.&lt;/p&gt;

&lt;p&gt;Whilst Package Signing and Author/Repository Trust will not stop all supply chain attacks from happening, it is at least a small part of the solution. We would welcome suggestions on where this can be improved&lt;/p&gt;

&lt;h3&gt;Software Bill of Materials (SBOM) Generation&lt;/h3&gt;

&lt;p&gt;The `dpm sbom` command will generate an SBOM for a project or project group - both CycloneDX and SPDX formats are supported. An HTML report is also produced for human consumption.&lt;/p&gt;

&lt;h3&gt;Vulnerability scanning&lt;/h3&gt;

&lt;p&gt;The `dpm scan &lt;sbom-or-project&gt; [options]` command will scan either a CycloneDX SBOM or a project/projectgroup and check it against the Open Source Vulnerabilities database at &lt;a href="https://osv.dev" target="_blank"&gt;https://osv.dev&lt;/a&gt; &lt;/sbom-or-project&gt;&lt;/p&gt;

&lt;h3&gt;Organisations&lt;/h3&gt;

&lt;p&gt;On some projects, more than one person might be allowed to publish packages. For this reason you can create an Organisation, and invite other users to join. This then allows them to publish under that organisation's name. It also makes life easier when a new maintainer takes over a project (just add them to the organisation).&lt;/p&gt;

&lt;p&gt;We have created organisations for some projects already, with the view that when the original project maintainers get on board with dpm (we hope) we can add them to the organisation and allow them to take control over it.&lt;/p&gt;

&lt;h3&gt;Reserved Prefixes&lt;/h3&gt;

&lt;p&gt;This is a server side feature that allows us to protect against people publishing packages that look as though they might come from another user. As an example, we publish our packages with the prefix VSoft.&lt;/p&gt;

&lt;p&gt;e.g VSoft.DUnitX, VSoft.AnsiConsole&lt;/p&gt;

&lt;p&gt;With the the reserved prefix no one else can publish a package with the prefix VSoft.&lt;/p&gt;

&lt;p&gt;They can of course publish their version of DUnitX with a different prefix - e.g MyUser.DUnitX&lt;/p&gt;

&lt;p&gt;We have added reserved prefixes for a bunch of well known libraries/authors - if you are one and get an error when trying to publish packages then contact us so we can assign the prefix to you. Our hope with this feature (and us preemptively adding well known prefixes) is that it will cut down on package name squatting.&lt;/p&gt;

&lt;h2&gt;Creating Packages&lt;/h2&gt;

&lt;p&gt;You might want to create packages if :&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;You have a library you want to share publicly or privately&lt;/li&gt;
	&lt;li&gt;You have a third party vendor libraries you want to standardize for internal use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that we do allow the publishing of commercial and trial/evaluation packages, provided they are flagged as such in their dspec.yaml&lt;/p&gt;

&lt;p&gt;The process is the same for both, only the publishing part is different.&lt;/p&gt;

&lt;p&gt;The first step is to create a package spec yaml file that defines the package and what it contains - e.g MyOrg.MyLibrary.dspec.yaml&lt;/p&gt;

&lt;p&gt;You can point the `dpm spec` command at your source folder, and it will attempt to scaffold a package spec file for you. It won't be usable immediately - but it will give you a head start.&lt;/p&gt;

&lt;p&gt;Once your dspec.yaml file is fully defined, use the `dpm pack MyOrg.MyLibrary.dspec.yaml -o=c:\mypackagesfolder` command to create the package files. The output be a .dpkg file for each compiler version your package supports.&lt;/p&gt;

&lt;p&gt;The next step (optional) is to &lt;a href="https://docs.delphi.dev/concepts/package-signing.html" target="_blank"&gt;sign&lt;/a&gt; the .dpkg files using a code signing certificate/&lt;/p&gt;

&lt;p&gt;Test the package locally to make sure it installs correctly. To do this, create a package source (`dpm sources add` command or from the IDE options) that points to your package output folder (the one you used in with pack command).&lt;/p&gt;

&lt;p&gt;If it fails, fix the dspec, pack it again, remove the package folder from the package cache (e.g `dpm cache remove MyOrg.MyLibrary -c 13.0 --version 1.2.0`) and try again.&lt;/p&gt;

&lt;p&gt;The final step is to publish the package - this is done using the `dpm push` command.&lt;/p&gt;

&lt;p&gt;If you are creating packages for internal use, you can just copy the files into the shared directory, however it is better to use the dpm push command - this speeds up usage of that directory as a package source (it extracts the icon, spec and writes the hash).&lt;/p&gt;

&lt;p&gt;If you are creating packages to share on delphi.dev then you need to follow a few steps.&lt;/p&gt;

&lt;ul style="list-style: none;"&gt;
	&lt;li&gt;1) Register on delphi.dev, enable 2 factor authentication.&lt;/li&gt;
	&lt;li&gt;2) Optionally create an Organisation (useful if you have a team creating/managing packages.)&lt;/li&gt;
	&lt;li&gt;3) If you signed your packages - register the public key on your account under "signing keys" (or org signing keys for an organisation).&lt;/li&gt;
	&lt;li&gt;4) Create an API Key - specify the package owner (yourself or your organisation)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With that done, use the `dpm push &lt;packagefile&gt; -source=dpm` command to push your packages to the dpm server.&lt;/packagefile&gt;&lt;/p&gt;

&lt;p&gt;If all goes well, the packages will show up in the dpm clients and website in a few minutes. They do first undergo some validation, virus scanning, repository signing before they are uploaded to the cloud storage.&lt;/p&gt;

&lt;h2&gt;Infrastructure&lt;/h2&gt;

&lt;p&gt;The &lt;a href="https://delphi.dev" target="_blank"&gt;delphi.dev&lt;/a&gt; site is hosted on our servers in Sydney, Australia. The site runs on a Proxmox virtual machine (linux) in a few docker containers, managed by &lt;a href="https://github.com/dokploy/dokploy" target="_blank"&gt;Dokploy&lt;/a&gt;. It uses a Postgresql DB (also in a container) and ClamAV (again in a container). The site is behind CloudFlare - with aggressive caching - we hope that will offset the latency that hosting downunder causes for the rest of the world. If this project garners enough support and donations (which we will enable at some point) to afford hosting elsewhere - we can quite easily move to a host somewhere more central (where most of the user are).&lt;/p&gt;

&lt;p&gt;The package files themselves are stored on CloudFlare R2 storage (US East) - which also does caching - the more people use dpm the faster downloading packages will become.&lt;/p&gt;

&lt;p&gt;DPM Clients also cache downloaded packages, so it avoids downloading package files every time you use a package on another project.&lt;/p&gt;

&lt;h2&gt;Is it finished?&lt;/h2&gt;

&lt;p&gt;Is any software ever really finished or perfect? DPM is currently in BETA, that means it's mostly feature complete - we're still tinkering around the edges, fixing bugs and improving performance - but it's relatively stable. We're using it here for FinalBuilder and Automise and on our CI servers. I encourage all Delphi developers to give it a go. I especially encourage library authors to take a look and consider creating packages for their libraries.&lt;/p&gt;

&lt;p&gt;DPM won't work for everyone or every project or every organisation - but it should work for most. One thing to note, DPM makes minimal (and easily removed) changes to your dproj files, and it will work alongside any third party libraries you already have installed.&lt;/p&gt;

&lt;p&gt;As always, feedback is welcomed.&lt;/p&gt;

&lt;ul style="list-style: none;"&gt;
	&lt;li&gt;Website : &lt;a href="https://delphi.dev" target="_blank"&gt;https://delphi.dev&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Client downloads : &lt;a href="https://github.com/DelphiPackageManager/DPM/releases/latest" target="_blank"&gt;https://github.com/DelphiPackageManager/DPM/releases/latest&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Client source code : &lt;a href="https://github.com/DelphiPackageManager/DPM" target="_blank"&gt;https://github.com/DelphiPackageManager/DPM&lt;/a&gt;&lt;/li&gt;
	&lt;li&gt;Server source code : &lt;a href="https://github.com/DelphiPackageManager/DPMServer" target="_blank"&gt;https://github.com/DelphiPackageManager/DPMServer&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt; &lt;/p&gt;
</description><guid isPermaLink="false">884</guid></item><item><title>FinalBuilder 8.6 and Automise 5.6 Release</title><link>https://www.finalbuilder.com/resources/blogs/postid/883/finalbuilder-86-and-automise-56-release</link><category>Automise,Delphi,FinalBuilder</category><pubDate>Tue, 26 May 2026 03:44:40 GMT</pubDate><description>&lt;p&gt;Today's release of FinalBuilder 8.6 and Automise 5.6 is important if you use the &lt;strong&gt;SFTP&lt;/strong&gt; actions in these products. &lt;/p&gt;

&lt;p&gt;This release includes re-implemented SFTP actions, in native code, using a new SFTP client library. This is something we have been wanting to for a few years now, the old library was no longer fit for purpose - it had bugs we were never able to resolve (since we never had the source code) and it did not support the newer algorithms. &lt;/p&gt;

&lt;p&gt;The actions have been tested with &lt;br /&gt;
&lt;br /&gt;
- OpenSSH 10.x&lt;br /&gt;
- Bitvise 9.x&lt;br /&gt;
&lt;br /&gt;
In addition we added support for newer Post Quantum key exchange algorithms :&lt;br /&gt;
- mlkem768x25519-sha256&lt;br /&gt;
- sntrup761x25519-sha512@openssh.com&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;IMPORTANT:&lt;/strong&gt; Before installing/running this release, ensure you have a backup of your project files (even better if they are in version control!). Project files saved with this version cannot be opened in older versions without information loss.&lt;br /&gt;
&lt;br /&gt;
Whilst we have done extensive testing, it was not possible for us to test with every SSH server implementation out there - so there may be issues. We suggest you test this version with your SSH server(s) before putting this version into production.&lt;/p&gt;
</description><guid isPermaLink="false">883</guid></item><item><title>Signing .rdp files with Signotaur (and surviving the April Windows update)</title><link>https://www.finalbuilder.com/resources/blogs/postid/882/signing-rdp-files-with-signotaur-and-surviving-the-april-windows-update</link><category>.NET,Code Signing,DelphiSignotaur,Windows</category><pubDate>Fri, 24 Apr 2026 02:27:48 GMT</pubDate><description>&lt;style type="text/css"&gt;div.blog_content h1 { font-size: 1.9rem; margin-bottom: 0.3rem; }
    div.blog_content h2 { font-size: 1.4rem; margin-top: 2.2rem; border-bottom: 1px solid #e0e0e0; padding-bottom: 0.4rem; }
    div.blog_content h3 { font-size: 1.15rem; margin-top: 1.6rem; color: #222;}
    div.blog_content strong {  font-weight: 600;  color: #888;}
    div.blog_content .meta { color: #777; font-size: 0.9rem; margin-bottom: 2rem; }
    div.blog_content code { background: #f4f4f4; padding: 0.15em 0.4em; border-radius: 3px; font-size: 0.92em; }
    div.blog_content pre { background: #f4f4f4; padding: 1rem; border-radius: 5px; overflow-x: auto; }
    div.blog_content pre code { background: none; padding: 0; }
    div.blog_content a { color: #0066cc; }
    div.blog_content img { max-width: 100%; border: 1px solid #ddd; border-radius: 4px; margin: 1rem 0; }
    div.blog_content .note { background: #eef6ff; border-left: 4px solid #0066cc; padding: 0.8rem 1rem; margin: 1.2rem 0; border-radius: 0 4px 4px 0; }
    div.blog_content ol { margin: 1rem 0 1.5rem 1.5rem; padding-left: 0.5rem;}
    div.blog_content ol li {  margin-bottom: 0.7rem;  line-height: 1.6;}
    div.blog_content ol li strong {  font-weight: 600;}
    div.blog_content ul li {  margin-bottom: 0.45rem;}
&lt;/style&gt;
&lt;div class="note"&gt;&lt;strong&gt;In this article:&lt;/strong&gt;
&lt;ul&gt;
	&lt;li&gt;What changed for signed &lt;code&gt;.rdp&lt;/code&gt; files in the April 2026 Windows update&lt;/li&gt;
	&lt;li&gt;Why previously-working signatures now show an orange warning dialog&lt;/li&gt;
	&lt;li&gt;The registry policy recipient machines need for no dialog at all&lt;/li&gt;
	&lt;li&gt;How Signotaur signs &lt;code&gt;.rdp&lt;/code&gt; files without distributing the certificate&lt;/li&gt;
	&lt;li&gt;Deploying the policy via Group Policy or PowerShell&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;p&gt;If you push Remote Desktop shortcuts out to users, you probably already know about the April 2026 Windows cumulative update (&lt;a href="https://support.microsoft.com/kb/5083769"&gt;KB5083769&lt;/a&gt; on Windows 11, KB5082200 on Windows 10). If you don't, you might have found out the hard way — via a Monday-morning deluge of "is this a virus?" tickets from users who suddenly have a big orange warning on the RDP file that worked fine last week.&lt;/p&gt;

&lt;p&gt;Signotaur 1.2.0.107 ships with &lt;code&gt;.rdp&lt;/code&gt; file signing support. Here's what changed in Windows, why it matters, and what the new signing command actually does.&lt;/p&gt;

&lt;h2&gt;What Microsoft changed&lt;/h2&gt;

&lt;p&gt;The April cumulative addresses &lt;a href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2026-26151"&gt;CVE-2026-26151&lt;/a&gt;. Two user-visible things came with it:&lt;/p&gt;

&lt;ol style="margin-left: 1.4em;  margin-bottom: 1em;"&gt;
	&lt;li&gt;The Remote Desktop Connection warning dialog was redesigned. It now lists every resource the connection can redirect (drives, printers, clipboard, USB, etc.) with individual checkboxes, and &lt;strong&gt;every box is off by default&lt;/strong&gt;. Users have to opt in to each one on every connection, every time.&lt;/li&gt;
	&lt;li&gt;The trust criteria for signed &lt;code&gt;.rdp&lt;/code&gt; files tightened. Pre-April, a file signed by an untrusted cert got a yellow "Verify the publisher" banner. Post-April, the same file gets an orange "Caution: Unknown remote connection" banner — visually indistinguishable from an unsigned file.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here's what the new per-launch dialog looks like. For an unsigned file:&lt;/p&gt;

&lt;p style="text-align: center;"&gt;&lt;img alt="The RDP security warning dialog for an unsigned file: an orange 'Caution: Unknown remote connection' banner, 'Unknown publisher', and per-redirection checkboxes all off by default." src="https://cdn.finalbuilder.com/blog/daves/signotaur-rdp/unsigned-rdp-security-warning-dialog.png" /&gt;&lt;/p&gt;

&lt;p&gt;And for a file signed by a publisher Windows can verify:&lt;/p&gt;

&lt;p style="text-align: center;"&gt;&lt;img alt="The RDP security warning dialog for a signed file: a yellow 'Verify the publisher of this remote connection' banner with the publisher name, and the same per-redirection checkboxes." src="https://cdn.finalbuilder.com/blog/daves/signotaur-rdp/signed-rdp-security-warning-dialog.png" /&gt;&lt;/p&gt;

&lt;p&gt;Separately, the first time any user opens an &lt;code&gt;.rdp&lt;/code&gt; file after installing the update, Windows shows a one-time educational dialog explaining what &lt;code&gt;.rdp&lt;/code&gt; files are and why they can be dangerous:&lt;/p&gt;

&lt;p style="text-align: center;"&gt;&lt;img alt="The first-launch educational dialog shown once per user account after installing KB5083769, explaining what RDP files are and the associated phishing risks." src="https://cdn.finalbuilder.com/blog/daves/signotaur-rdp/rdp-first-launch-dialog.png" /&gt;&lt;/p&gt;

&lt;p&gt;Once dismissed, it doesn't reappear for that account.&lt;/p&gt;

&lt;p&gt;Discussion and lament: &lt;a href="https://www.reddit.com/r/sysadmin/comments/1sm61eo/fyi_microsoft_rdp_changes_with_april_cumulative/"&gt;r/sysadmin: FYI: Microsoft RDP changes with April cumulative&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is a genuinely good security change — the old dialog was vague and under-informed users about what was being shared with the remote host. It is also a rather annoying deployment change, because plenty of teams had &lt;code&gt;rdpsign.exe&lt;/code&gt;-signed files quietly working for years, and now they don't.&lt;/p&gt;

&lt;h2&gt;Why people got caught out&lt;/h2&gt;

&lt;p&gt;The usual story goes like this: a team signed their &lt;code&gt;.rdp&lt;/code&gt; file years ago with a self-signed or internal-CA certificate, shipped it to users, and it displayed a friendly yellow "Verify the publisher: Acme Corp" dialog that everyone clicked through. After April's update, the same file suddenly shows an orange "Unknown remote connection" dialog and support gets flooded. One representative example from the Reddit threads: &lt;a href="https://www.reddit.com/r/sysadmin/comments/1sp6h4x/comment/ohaenxv/"&gt;a sysadmin describing exactly this&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The signatures on those files are still cryptographically valid. Windows is just stricter now about what counts as a "verified publisher" for RDP.&lt;/p&gt;

&lt;h2&gt;The actual recipe (no dialog at all)&lt;/h2&gt;

&lt;p&gt;Cutting through the noise, here's what recipient machines need for a signed &lt;code&gt;.rdp&lt;/code&gt; file to open with no warning dialog at all:&lt;/p&gt;

&lt;ol style="margin-left: 1.4em;  margin-bottom: 1em;"&gt;
	&lt;li&gt;The signing certificate's chain must terminate in a root the client machine trusts. Commercial code-signing certs (DigiCert, Sectigo, etc.) chain to roots Windows already trusts. For an internal CA or self-signed cert, the root has to be imported into &lt;code&gt;Cert:\*\Root&lt;/code&gt; on each client.&lt;/li&gt;
	&lt;li&gt;A Remote Desktop trust policy must be in place that whitelists your signing certificate's SHA-1 thumbprint. This lives at either &lt;code&gt;HKLM\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services&lt;/code&gt; (machine-wide, requires admin) or &lt;code&gt;HKCU\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services&lt;/code&gt; (per-user, no admin required), and needs two values:
	&lt;ul style="margin-bottom: 0.5em;"&gt;
		&lt;li&gt;&lt;code&gt;AllowSignedFiles&lt;/code&gt; — REG_DWORD, set to &lt;code&gt;1&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;TrustedCertThumbprints&lt;/code&gt; — REG_SZ, the SHA-1 thumbprint of your signing cert, uppercase, no spaces (semicolon-separated if you have more than one)&lt;/li&gt;
	&lt;/ul&gt;
	&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A word of warning about one trap we hit: &lt;code&gt;TrustedCertThumbprints&lt;/code&gt; is a whitelist on top of normal chain validation, not a replacement for it. Dropping a self-signed cert's thumbprint into the list without also importing the cert into a trusted root store does nothing. If you've tried this and wondered why it didn't work, that's why.&lt;/p&gt;

&lt;h2&gt;What Signotaur does when you sign a .rdp file&lt;/h2&gt;

&lt;p&gt;Unlike &lt;code&gt;rdpsign.exe&lt;/code&gt;, Signotaur signs &lt;code&gt;.rdp&lt;/code&gt; files against a remote server — the private key stays on the server (or an HSM it's connected to), so no admin workstation or automation host needs a local copy of the signing certificate. This is the main reason to use Signotaur for &lt;code&gt;.rdp&lt;/code&gt; signing rather than running &lt;code&gt;rdpsign.exe&lt;/code&gt; directly.&lt;/p&gt;

&lt;p&gt;The mechanics otherwise match what you'd expect. The client reads the &lt;code&gt;.rdp&lt;/code&gt; file, canonicalises the contents, sends only the digest to the server for signing, and writes the signed file back in place. The output is byte-equivalent to &lt;code&gt;rdpsign.exe&lt;/code&gt;'s — same canonical form, same 12-byte Microsoft wrapper, same detached CMS structure — so recipients see the same Windows Remote Desktop Connection dialog regardless of which tool produced the signature.&lt;/p&gt;
        &lt;p&gt;RFC 3161 timestamping is supported, and the timestamp is embedded into the CMS in the standard way. But there's a caveat that's easy to miss: &lt;code&gt;mstsc.exe&lt;/code&gt; doesn't actually consult the timestamp when validating a &lt;code&gt;.rdp&lt;/code&gt; signature — it only checks whether the signing certificate is currently valid at the moment the file is opened. The strongest indirect evidence for this is that Microsoft's own &lt;code&gt;rdpsign.exe&lt;/code&gt; has no timestamping support at all — no &lt;code&gt;/tr&lt;/code&gt; flag, no timestamp in its output.&lt;/p&gt;
        &lt;p&gt;The timestamp is still worth having: it's standards-compliant CMS so general-purpose tools can read the signing time, it provides a tamper-evident audit trail, and it future-proofs against any future change in &lt;code&gt;mstsc&lt;/code&gt;'s behaviour. In practice though, plan to re-sign distributed &lt;code&gt;.rdp&lt;/code&gt; files when your signing certificate is renewed, the same way you would for an unsigned-but-distributed file.&lt;/p&gt;

&lt;p&gt;Because the registry recipe above is easy to get wrong, Signotaur also prints the recipe for you after signing, pre-filled with the thumbprint of the certificate that just signed the file. It tells you whether the cert is self-signed (in which case you'll also need to deploy the cert itself to recipient trusted-root stores) or chained (in which case you may not).&lt;/p&gt;

&lt;p&gt;If you're running &lt;code&gt;sign&lt;/code&gt; interactively on Windows, it also offers to apply the policy to &lt;code&gt;HKCU&lt;/code&gt; for the current user on the spot — no admin rights needed, no registry editor, no PowerShell snippet to copy-paste. This is mostly useful for confirming the signing works locally before you deploy the policy via GPO. In unattended runs, the prompt is automatically skipped, and you can pass &lt;code&gt;--no-mstsc-guidance&lt;/code&gt; (&lt;code&gt;--nmg&lt;/code&gt;) to suppress the whole lot if the log gets noisy.&lt;/p&gt;

&lt;h2&gt;An example&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;sign&lt;/code&gt; command detects &lt;code&gt;.rdp&lt;/code&gt; files automatically based on extension, so there's nothing special to type:&lt;/p&gt;

&lt;div&gt;
&lt;div class="syntaxhighlighter  bash" id="highlighter_rdpsign"&gt;
&lt;table border="0" cellpadding="0" cellspacing="0"&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td class="gutter"&gt;
			&lt;div class="line number1 index0 alt2"&gt;&gt;&lt;/div&gt;
			&lt;/td&gt;
			&lt;td class="code"&gt;
			&lt;div class="container"&gt;
			&lt;div class="line number1 index0 alt2"&gt;&lt;code class="bash plain"&gt;SignotaurTool.exe sign -a &lt;apikey&gt; -s &lt;signserver&gt; -t &lt;thumbprint&gt; --tr http://timestamp.digicert.com --td SHA256 connect-to-prod.rdp&lt;/thumbprint&gt;&lt;/signserver&gt;&lt;/apikey&gt;&lt;/code&gt;&lt;/div&gt;
			&lt;/div&gt;
			&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;After a successful sign you'll see something along the lines of:&lt;/p&gt;

&lt;pre style="margin-bottom: 1em;"&gt;
&lt;code&gt;RDP signing guidance (Windows Remote Desktop Connection compatibility, post-KB5083769):

By default recipients will see a "Verify the publisher" or "Unknown publisher"
warning dialog when opening this signed file in Windows Remote Desktop Connection.
To eliminate the warning, each recipient machine needs:

1. The signing certificate's chain trusted on the machine.
   For commercial certificates chaining to a Windows-preinstalled root, no action
   is required; internal-CA certificates require the CA to be imported into each
   recipient's Trusted Root store.

2. The signing certificate's thumbprint added to the Remote Desktop trust-publisher
   policy:

   Value: AllowSignedFiles (REG_DWORD) = 1
   Value: TrustedCertThumbprints (REG_SZ) = &lt;your_cert_thumbprint&gt;

Apply AllowSignedFiles + TrustedCertThumbprints to your current user registry now?
Useful for testing this signed .rdp locally. [y/N]:&lt;/your_cert_thumbprint&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Answer &lt;code&gt;y&lt;/code&gt; and it writes the values to your &lt;code&gt;HKCU&lt;/code&gt; — open the file in Remote Desktop Connection, confirm there's no dialog, and you know the signing bit is working before you take the policy near a GPO.&lt;/p&gt;

&lt;h2&gt;Deploying the policy to the fleet&lt;/h2&gt;

&lt;p&gt;For anything beyond a couple of machines, Group Policy is the right tool — it's also how you set these same values without touching the registry by hand. In the Group Policy Management Editor:&lt;/p&gt;

&lt;ul style="margin-bottom: 1em;"&gt;
	&lt;li&gt;Computer (or User) Configuration → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Connection Client&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Allow .rdp files from valid publishers and user's default .rdp settings&lt;/em&gt; → Enabled&lt;/li&gt;
	&lt;li&gt;&lt;em&gt;Specify SHA1 thumbprints of certificates representing trusted .rdp publishers&lt;/em&gt; → Enabled, with your thumbprints in the list (uppercase, semicolon-separated if multiple)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Intune has equivalent settings under the Administrative Templates profile. If you're deploying to a smaller set of machines, or scripting it, a PowerShell snippet that does the per-user version (no admin needed) looks like this:&lt;/p&gt;

&lt;div&gt;
&lt;div class="syntaxhighlighter  powershell" id="highlighter_psrecipe"&gt;
&lt;table border="0" cellpadding="0" cellspacing="0"&gt;
	&lt;tbody&gt;
		&lt;tr&gt;
			&lt;td class="gutter"&gt;
			&lt;div class="line number1 index0 alt2"&gt;1&lt;/div&gt;

			&lt;div class="line number2 index1 alt1"&gt;2&lt;/div&gt;

			&lt;div class="line number3 index2 alt2"&gt;3&lt;/div&gt;

			&lt;div class="line number4 index3 alt1"&gt;4&lt;/div&gt;
			&lt;/td&gt;
			&lt;td class="code"&gt;
			&lt;div class="container"&gt;
			&lt;div class="line number1 index0 alt2"&gt;&lt;code class="powershell plain"&gt;$p = 'HKCU:\SOFTWARE\Policies\Microsoft\Windows NT\Terminal Services'&lt;/code&gt;&lt;/div&gt;

			&lt;div class="line number2 index1 alt1"&gt;&lt;code class="powershell plain"&gt;New-Item -Path $p -Force | Out-Null&lt;/code&gt;&lt;/div&gt;

			&lt;div class="line number3 index2 alt2"&gt;&lt;code class="powershell plain"&gt;Set-ItemProperty -Path $p -Name AllowSignedFiles -Value 1 -Type DWord&lt;/code&gt;&lt;/div&gt;

			&lt;div class="line number4 index3 alt1"&gt;&lt;code class="powershell plain"&gt;Set-ItemProperty -Path $p -Name TrustedCertThumbprints -Value 'YOUR_THUMBPRINT_UPPERCASE' -Type String&lt;/code&gt;&lt;/div&gt;
			&lt;/div&gt;
			&lt;/td&gt;
		&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;

&lt;p&gt;Swap &lt;code&gt;HKCU&lt;/code&gt; for &lt;code&gt;HKLM&lt;/code&gt; for the machine-wide version (and run elevated). The thumbprint must be uppercase with no spaces; use a semicolon to join multiple thumbprints if you have more than one signing cert in rotation.&lt;/p&gt;

&lt;h2&gt;What you still can't do&lt;/h2&gt;

&lt;p&gt;A few things worth knowing up front so you don't hunt for them:&lt;/p&gt;

&lt;ul style="margin-bottom: 1em;"&gt;
	&lt;li&gt;The per-redirection checkboxes in the new dialog are not controlled by &lt;code&gt;AllowSignedFiles&lt;/code&gt;. Even with a properly trusted and whitelisted signature, users still see the redirection dialog on first use. There's a separate set of policies for which redirections are allowed on the server side; the client-side checkboxes are a user-consent UI rather than a trust decision.&lt;/li&gt;
	&lt;li&gt;There's a temporary "revert to pre-April dialog" switch at &lt;code&gt;HKLM\Software\Policies\Microsoft\Windows NT\Terminal Services\Client\RedirectionWarningDialogVersion = 1&lt;/code&gt;. Don't rely on it — Microsoft has been explicit that it will be removed in a future update.&lt;/li&gt;
	&lt;li&gt;Windows has no built-in &lt;code&gt;.rdp&lt;/code&gt; signature verifier. &lt;code&gt;rdpsign.exe /v&lt;/code&gt; is "verbose", not "verify"; in practice the only verifier is Remote Desktop Connection opening the file. Signotaur's &lt;code&gt;verify&lt;/code&gt; command will validate the signature and cert chain offline if you want a CI-friendly check.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;If you'd rather not think about any of this&lt;/h2&gt;

&lt;p&gt;The short version: get a code-signing certificate from a public CA that chains to a Windows-preinstalled root, register it with your Signotaur server, sign your &lt;code&gt;.rdp&lt;/code&gt; files as part of your distribution workflow, and push the &lt;code&gt;AllowSignedFiles&lt;/code&gt; + &lt;code&gt;TrustedCertThumbprints&lt;/code&gt; policy out via GPO. After that, signed &lt;code&gt;.rdp&lt;/code&gt; files open with no dialog, and the next time Microsoft tightens the rules you've already done the trust-deployment work.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;For command-line details and the full signing command reference see the &lt;a href="https://docs.finalbuilder.com/sn/1.0/"&gt;Signotaur documentation&lt;/a&gt;. If you run into something specific — especially if you have an internal CA or a less-common PKCS#11 token in play — our support team is happy to help.&lt;/p&gt;
</description><guid isPermaLink="false">882</guid></item><item><title>Managing Certificate and API Key Expiry with Signotaur</title><link>https://www.finalbuilder.com/resources/blogs/postid/879/managing-certificate-and-api-key-expiry-with-signotaur</link><category>.NET,Code Signing,Continua CI,Delphi,FinalBuilderSignotaur</category><pubDate>Fri, 13 Mar 2026 03:18:12 GMT</pubDate><description>&lt;style type="text/css"&gt;
	div.blog_content h1 { font-size: 1.9rem; margin-bottom: 0.3rem; }
    div.blog_content h2 { font-size: 1.4rem; margin-top: 2.2rem; border-bottom: 1px solid #e0e0e0; padding-bottom: 0.4rem; }
    div.blog_content h3 { font-size: 1.15rem; margin-top: 1.6rem; color: #222;}
    div.blog_content strong {  font-weight: 600;  color: #888;}
    div.blog_content .meta { color: #777; font-size: 0.9rem; margin-bottom: 2rem; }
    div.blog_content code { background: #f4f4f4; padding: 0.15em 0.4em; border-radius: 3px; font-size: 0.92em; }
    div.blog_content pre { background: #f4f4f4; padding: 1rem; border-radius: 5px; overflow-x: auto; }
    div.blog_content pre code { background: none; padding: 0; }
    div.blog_content a { color: #0066cc; }
    div.blog_content img { max-width: 100%; border: 1px solid #ddd; border-radius: 4px; margin: 1rem 0; }
    div.blog_content .note { background: #eef6ff; border-left: 4px solid #0066cc; padding: 0.8rem 1rem; margin: 1.2rem 0; border-radius: 0 4px 4px 0; }
    div.blog_content ol { margin: 1rem 0 1.5rem 1.5rem; padding-left: 0.5rem;}
    div.blog_content ol li {  margin-bottom: 0.7rem;  line-height: 1.6;}
    div.blog_content ol li strong {  font-weight: 600;}
    div.blog_content ul li {  margin-bottom: 0.45rem;}
&lt;/style&gt;
&lt;div class="note"&gt;&lt;strong&gt;In this article:&lt;/strong&gt;
&lt;ul&gt;
	&lt;li&gt;Why code signing certificates now expire sooner&lt;/li&gt;
	&lt;li&gt;How certificate labels remove thumbprints from build scripts&lt;/li&gt;
	&lt;li&gt;How to rotate and renew API keys safely&lt;/li&gt;
	&lt;li&gt;How to automate the process in Continua CI&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;h2&gt;Shorter Certificate Lifetimes Are Coming&lt;/h2&gt;

&lt;p&gt;Code signing certificates used to last up to three years. As of &lt;strong&gt;March 1, 2026&lt;/strong&gt;, that is no longer the case.&lt;/p&gt;

&lt;p&gt;The CA/Browser Forum adopted &lt;strong&gt;Ballot CSC-31&lt;/strong&gt; on November 17, 2025, reducing the maximum validity period for publicly-trusted code signing certificates from 39 months to &lt;strong&gt;460 days&lt;/strong&gt; (roughly 15 months). For most teams, that means certificate renewals are now an annual operational task rather than an occasional one.&lt;/p&gt;

&lt;p&gt;When a certificate is renewed, it receives a new thumbprint, and build scripts that reference the old thumbprint must be updated. In large CI/CD environments, tracking down every reference can be tedious and error-prone.&lt;/p&gt;

&lt;p&gt;Separately, API keys used by CI agents to authenticate with the signing server have their own lifecycle and eventually need to be rotated. Replacing them without interrupting active build pipelines can be challenging.&lt;/p&gt;

&lt;p&gt;Signotaur addresses both concerns. &lt;strong&gt;Label-based certificate selection&lt;/strong&gt; decouples build pipelines from individual certificates, while &lt;strong&gt;API key rotation with overlap&lt;/strong&gt; allows credentials to be replaced without downtime. Together they turn what used to be stressful maintenance tasks into routine operations.&lt;/p&gt;

&lt;h2&gt;Certificate Labels: Automatic Certificate Rotation&lt;/h2&gt;

&lt;h3&gt;The Thumbprint Problem&lt;/h3&gt;

&lt;p&gt;Traditionally, build scripts reference a code signing certificate by its SHA-1 thumbprint — a 40-character hex string that uniquely identifies the certificate. When you renew, you get a new certificate with a new thumbprint, so every script that signs code needs to be updated. If you sign across multiple CI configurations, that means tracking down and editing each one.&lt;/p&gt;

&lt;h3&gt;Labels to the Rescue&lt;/h3&gt;

&lt;p&gt;Signotaur lets you assign a &lt;strong&gt;label&lt;/strong&gt; to each registered certificate — for example, &lt;code&gt;production&lt;/code&gt; or &lt;code&gt;nightly&lt;/code&gt;. When you request a signing operation by label instead of thumbprint, Signotaur automatically selects the certificate with the &lt;strong&gt;latest expiry date&lt;/strong&gt; among all enabled, non-expired certificates that share that label. This ensures that newly issued certificates automatically take precedence.&lt;/p&gt;

&lt;p&gt;The rotation workflow is straightforward:&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;Register your renewed certificate and assign it the same label as the outgoing one.&lt;/li&gt;
	&lt;li&gt;Builds automatically pick up the new certificate — no script changes required.&lt;/li&gt;
	&lt;li&gt;The old certificate expires naturally; remove it from Signotaur when you're ready.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;Expiration Monitoring&lt;/h3&gt;

&lt;p&gt;Signotaur's background monitoring service checks certificate expiration &lt;strong&gt;daily&lt;/strong&gt; and sends email notifications to administrators at configurable intervals. The defaults are &lt;strong&gt;30, 14, 7, 3, and 1 day(s)&lt;/strong&gt; before expiry, with an additional alert if a certificate has already expired. You can customise these warning thresholds in the server configuration.&lt;/p&gt;

&lt;p&gt;During a rotation window — when both the old and new certificates are registered with the same label — the admin UI highlights the duplicate label so you can confirm the overlap is intentional.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Certificate list in the Signotaur admin UI showing two certificates sharing the 'production' label. The older certificate shows an expiry warning badge." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-cert-labels.png" /&gt;&lt;/p&gt;

&lt;h2&gt;API Key Rotation with Overlap&lt;/h2&gt;

&lt;h3&gt;Why Rotate Keys?&lt;/h3&gt;

&lt;p&gt;API keys grant access to your signing service. If a key is leaked or reused indefinitely, it becomes a long-lived security risk. Regular rotation limits the impact if a key is compromised, satisfies compliance requirements, and handles natural key expiry gracefully. But naive rotation — revoke old, issue new — creates a window where CI agents holding the old key start failing.&lt;/p&gt;

&lt;h3&gt;How Signotaur Handles It&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;rotate-key&lt;/code&gt; command creates a new API key while keeping the old one valid for a configurable &lt;strong&gt;overlap period&lt;/strong&gt; of &lt;strong&gt;0–30 days&lt;/strong&gt; (default: &lt;strong&gt;7 days&lt;/strong&gt;). During this window, both keys are accepted, allowing CI agents and environments to transition without interruption.&lt;/p&gt;

&lt;p&gt;Once the overlap period expires, the old key is &lt;strong&gt;automatically revoked&lt;/strong&gt;. If you prefer to manage revocation manually, pass &lt;code&gt;--no-auto-revoke&lt;/code&gt; and the old key will remain valid until you explicitly revoke it.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: API Keys page in the Signotaur admin UI showing a rotated key pair. The old key displays an 'Auto-revoke' date and the new key is marked as active." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-api-key-rotation.png" /&gt;&lt;/p&gt;

&lt;h3&gt;Safety Guardrails&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Role required&lt;/strong&gt; — users must be assigned the &lt;strong&gt;ApiKeyRotator&lt;/strong&gt; role before they can rotate keys. An administrator can assign this role in the Signotaur admin UI.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Rate limiting&lt;/strong&gt; — a maximum of 5 rotations per user per 24-hour period prevents accidental key sprawl.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Linear chain only&lt;/strong&gt; — a key that has already been rotated cannot be rotated again; you must use the successor key. This prevents branching into multiple active key chains.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Proactive expiry checking&lt;/strong&gt; — the sign command accepts a &lt;code&gt;--fail-if-expiring-within&lt;/code&gt; flag (e.g. &lt;code&gt;14d&lt;/code&gt;). If the API key used for signing will expire within that window, the command fails immediately with a clear message — catching the problem in CI before it causes a real signing failure.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Conditional Rotation&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;--if-expiring-within&lt;/code&gt; flag on &lt;code&gt;rotate-key&lt;/code&gt; makes rotation idempotent: the key is only rotated if it expires within the specified duration (e.g. &lt;code&gt;14d&lt;/code&gt;, &lt;code&gt;1w&lt;/code&gt;, &lt;code&gt;24h&lt;/code&gt;). This makes it safe to run &lt;code&gt;rotate-key&lt;/code&gt; on every CI build or on a nightly schedule without generating unnecessary keys.&lt;/p&gt;

&lt;p&gt;Example scheduled rotation command:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;signotaur rotate-key --if-expiring-within 14d&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Key Renewal&lt;/h3&gt;

&lt;p&gt;By default, a rotated key &lt;strong&gt;inherits the old key's expiry date&lt;/strong&gt;. If the old key had 30 days of validity remaining, the new key also expires in 30 days. Over time, repeatedly rotating a key gradually shortens its remaining lifetime — which can be a problem for long-running automation.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;--renew&lt;/code&gt; flag gives the new key a &lt;strong&gt;fresh validity period&lt;/strong&gt; starting from the rotation date, rather than inheriting whatever time was left on the old key. Without a value, it uses the server default of &lt;strong&gt;90 days&lt;/strong&gt;; with a value (e.g. &lt;code&gt;--renew 180d&lt;/code&gt;), it sets a specific duration up to a maximum of &lt;strong&gt;365 days&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;This pairs naturally with conditional rotation — check whether the key is approaching expiry, and if so, rotate and renew in a single command:&lt;/p&gt;

&lt;pre&gt;
&lt;code&gt;signotaur rotate-key --if-expiring-within 14d --renew&lt;/code&gt;&lt;/pre&gt;

&lt;div class="note"&gt;If the renewal duration would be &lt;em&gt;shorter&lt;/em&gt; than the old key's remaining validity (for example renewing for 30 days when 60 days remain), the command fails as a safety measure. Pass &lt;code&gt;--allow-validity-reduction&lt;/code&gt; to override this check when the shorter duration is intentional.&lt;/div&gt;

&lt;h2&gt;Putting It Together in Continua CI&lt;/h2&gt;

&lt;p&gt;Continua CI ships dedicated &lt;strong&gt;Signotaur actions&lt;/strong&gt; for both signing and key rotation, so you can wire up the entire workflow without writing any custom scripts. Before configuring those actions, you'll need to assign a label to your certificates in the Signotaur admin UI.&lt;/p&gt;

&lt;h3&gt;Assigning a Label to Your Certificates&lt;/h3&gt;

&lt;p&gt;In the Signotaur admin UI, navigate to &lt;strong&gt;Certificates&lt;/strong&gt; and either add a new certificate or edit an existing one. In the certificate dialog you'll find two name fields:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Alias&lt;/strong&gt; — a unique display name for the certificate (auto-generated by default, e.g. "CodeSigningCert (2027-12-31)").&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt; — an optional identifier used for CLI and CI/CD certificate selection, e.g. &lt;code&gt;production&lt;/code&gt;. Multiple certificates can share the same label. Matching is case-insensitive, so &lt;code&gt;Production&lt;/code&gt; and &lt;code&gt;production&lt;/code&gt; resolve the same way.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you renew a certificate, register the new one and assign it the same label as the outgoing certificate. The admin UI will show an orange notice confirming that multiple active certificates share the label and that the one with the latest expiry will be selected automatically. No build script changes needed.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Signotaur certificate edit dialog showing the Alias and Label fields. The Label field is set to 'production'." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-cert-edit-label.png" /&gt;&lt;/p&gt;

&lt;p&gt;For full details, see the &lt;a href="https://docs.finalbuilder.com/sn/1.0/server/admin/certificates/certificates.html"&gt; Certificates documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;Setting Up the Rotate Keys Action&lt;/h3&gt;

&lt;p&gt;Add the &lt;strong&gt;Signotaur Rotate Keys&lt;/strong&gt; action to a stage — either in a scheduled maintenance configuration or directly in your build configuration. With the &lt;strong&gt;If Expiring Within&lt;/strong&gt; condition the action only rotates the key when expiry is approaching, so it can safely run on every build.&lt;/p&gt;

&lt;p&gt;The action is organised into several tabs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Signotaur Rotate Keys tab&lt;/strong&gt; — configure &lt;strong&gt;Overlap Days&lt;/strong&gt; (how long the old key remains valid alongside the new one, default 7) and whether to &lt;strong&gt;Disable auto-revocation&lt;/strong&gt; if you prefer to revoke old keys manually.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Rotate Keys action — Main tab showing Overlap Days and Disable auto-revocation options." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-rotate-keys-main.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Server tab&lt;/strong&gt; — set the &lt;strong&gt;Server URL&lt;/strong&gt; for your Signotaur instance and the &lt;strong&gt;API Key Source&lt;/strong&gt;. Select &lt;em&gt;Value (from variable)&lt;/em&gt; and reference a server variable (e.g. &lt;code&gt;%SignotaurAPIKey%&lt;/code&gt;) to avoid hard-coding keys in the action.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Rotate Keys action — Server tab showing Server URL and API Key Source set to a server variable." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-rotate-keys-server.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conditions tab&lt;/strong&gt; — set &lt;strong&gt;If Expiring Within&lt;/strong&gt; to make the rotation conditional (e.g. &lt;code&gt;14d&lt;/code&gt; to only rotate if expiry is within two weeks). Enable &lt;strong&gt;Ignore already rotated error&lt;/strong&gt; to safely run the action in concurrent CI builds without failure if the key was already rotated by another build.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Rotate Keys action — Conditions tab showing If Expiring Within and Ignore already rotated error options." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-rotate-keys-conditions.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Renewal tab&lt;/strong&gt; — enable the &lt;strong&gt;Renew&lt;/strong&gt; checkbox to give the new key a fresh validity period instead of inheriting the old key's remaining lifetime. Set a specific &lt;strong&gt;Renew Duration&lt;/strong&gt; (e.g. &lt;code&gt;90d&lt;/code&gt;), or leave it blank to use the server default. Check &lt;strong&gt;Allow validity reduction&lt;/strong&gt; if the renewal duration may be shorter than the old key's remaining validity.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Rotate Keys action — Renewal tab showing Renew checkbox, Renew Duration, and Allow validity reduction options." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-rotate-keys-renewal.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Output tab&lt;/strong&gt; — choose &lt;strong&gt;Set Variable&lt;/strong&gt; as the output destination and select a &lt;strong&gt;Server variable&lt;/strong&gt; to store the new key. This way your sign actions automatically pick up the rotated key without any manual updates.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Rotate Keys action — Output tab with Set Variable selected, storing the new key in a server-scoped variable." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-rotate-keys-output.png" /&gt;&lt;/p&gt;

&lt;p&gt;Full documentation: &lt;a href="https://docs.finalbuilder.com/ci/1.0/user-guide/actions/signing-actions/signotaur-rotate-keys-action.html"&gt; Signotaur Rotate Keys Action &lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;Setting Up the Sign Action with Label Selection&lt;/h3&gt;

&lt;p&gt;Add the &lt;strong&gt;Signotaur Sign&lt;/strong&gt; action to your build stage, after compilation and before packaging.&lt;/p&gt;

&lt;p&gt;Key fields:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Files to Sign&lt;/strong&gt; — glob patterns for your build output, e.g. &lt;code&gt;**/*.exe&lt;/code&gt;, &lt;code&gt;**/*.dll&lt;/code&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Certificate Selection Mode&lt;/strong&gt; — set to &lt;strong&gt;Label&lt;/strong&gt;.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Label&lt;/strong&gt; — your shared label, e.g. &lt;code&gt;production&lt;/code&gt;. Signotaur will automatically select the certificate with the latest expiry date.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;API Key Source&lt;/strong&gt; — point to the server variable populated by the Rotate Keys action, or a securely stored key.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Fail If Expiring Within&lt;/strong&gt; — e.g. &lt;code&gt;14d&lt;/code&gt;. If the API key expires within two weeks, the action fails early so you can rotate before it becomes a blocker.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Timestamp Server &amp; Digest&lt;/strong&gt; — configure your preferred timestamping authority and hash algorithm.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Sign action — Certificate tab showing Selection Mode set to Label with value 'production'." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-sign-certificate.png" /&gt; 
&lt;/p&gt;
&lt;p&gt;&lt;img alt="Screenshot: Continua CI Signotaur Sign action — Server tab showing Fail If Expiring Within set to '14d'." src="https://cdn.finalbuilder.com/blog/daves/managing-certificate-and-api-key-expiry/screenshot-sign-server.png" /&gt;&lt;/p&gt;

&lt;p&gt;Full documentation: &lt;a href="https://docs.finalbuilder.com/ci/1.0/user-guide/actions/signing-actions/signotaur-sign-action.html"&gt; Signotaur Sign Action &lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;Typical Rotation Workflow&lt;/h2&gt;

&lt;p&gt;In practice, certificate and API key rotation can be handled with a small amount of scheduled automation in your CI system.&lt;/p&gt;

&lt;ol&gt;
	&lt;li&gt;&lt;strong&gt;Register renewed certificates&lt;/strong&gt; in Signotaur and assign them the same label as the previous certificate.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;CI builds continue using the label&lt;/strong&gt;, automatically selecting the certificate with the latest expiry date.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Schedule periodic API key checks&lt;/strong&gt; using the &lt;code&gt;rotate-key --if-expiring-within&lt;/code&gt; option.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;The new key is written to a CI server variable&lt;/strong&gt;, allowing build pipelines to automatically use the rotated key.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;--renew&lt;/code&gt;&lt;/strong&gt; so rotated keys receive a fresh validity period rather than inheriting the old key's remaining lifetime.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Retire old certificates and keys&lt;/strong&gt; once they are no longer needed.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;Wrapping Up&lt;/h2&gt;

&lt;p&gt;With code signing certificate lifetimes dropping to roughly 15 months, the days of "set it and forget it" certificate management are over. Signotaur's label-based signing means your CI/CD pipelines don't need to know — or care — which specific certificate is current. And overlap-based API key rotation ensures you can swap credentials without any signing downtime.&lt;/p&gt;

&lt;p&gt;These features are already available in Signotaur. If you're evaluating it, check out the &lt;a href="https://docs.finalbuilder.com/signotaur/1.0/"&gt;Signotaur documentation&lt;/a&gt; to get started.&lt;/p&gt;
</description><guid isPermaLink="false">879</guid></item><item><title>Black Friday Sale 2025 - 40% off all new licenses - Extended!</title><link>https://www.finalbuilder.com/resources/blogs/postid/877/black-friday-sale-2025-40-off-all-new-licenses</link><category>Delphi</category><pubDate>Sun, 23 Nov 2025 23:20:19 GMT</pubDate><description>&lt;p&gt;&lt;strong&gt;Black Friday Sale&lt;/strong&gt; - &lt;strong&gt;&lt;span style="color:#ff0000;"&gt;40%&lt;/span&gt;&lt;/strong&gt; off all new licenses until midnight (utc) 9th December 2025.&lt;/p&gt;

&lt;p&gt;No coupon code required, the store will apply the discount automatically.&lt;/p&gt;
</description><guid isPermaLink="false">877</guid></item><item><title>ClickOnce and VSTO Application Signing with Signotaur</title><link>https://www.finalbuilder.com/resources/blogs/postid/876/clickonce-and-vsto-application-signing-with-signotaur</link><category>.NET,Code Signing,Continua CI,Delphi,Deployment,Signotaur</category><pubDate>Tue, 14 Oct 2025 00:23:40 GMT</pubDate><description>&lt;p&gt;&lt;/p&gt;&lt;p&gt;If you've been working with ClickOnce or VSTO applications, you know that signing them isn't quite like signing a regular executable. We're pleased to announce that Signotaur now handles ClickOnce and VSTO application signing, taking care of the manifest orchestration so you don't have to.&lt;/p&gt;

        &lt;h2&gt;What Makes ClickOnce and VSTO Different?&lt;/h2&gt;
        
        &lt;p&gt;When you sign a standard executable or DLL, you're dealing with a single file. The process is straightforward: calculate a hash, sign it, embed the signature. One file, one operation.&lt;/p&gt;
        
        &lt;p&gt;ClickOnce and VSTO applications are a different beast entirely. These deployment packages consist of multiple files tied together by manifest files that describe the application structure, dependencies, and deployment configuration. The challenge? Everything needs to be signed in a specific order, and those manifests need to be updated with new hash values after each signing operation.&lt;/p&gt;
        
        &lt;p&gt;Here's what's happening under the hood:&lt;/p&gt;
        &lt;ol style="margin-left: 1.4em;  margin-bottom: 1em;"&gt;
            &lt;li&gt;&lt;strong&gt;Application files&lt;/strong&gt; get signed first (your assemblies, dependencies, etc.)&lt;/li&gt;
            &lt;li&gt;The &lt;strong&gt;application manifest (.manifest)&lt;/strong&gt; needs to be updated with the new hash values of those signed files&lt;/li&gt;
            &lt;li&gt;Then the application manifest itself gets signed&lt;/li&gt;
            &lt;li&gt;The &lt;strong&gt;deployment manifest (.application)&lt;/strong&gt; needs to be updated with the hash of the signed application manifest&lt;/li&gt;
            &lt;li&gt;Finally, the deployment manifest gets signed&lt;/li&gt;
        &lt;/ol&gt;
        
        &lt;p&gt;Miss a step or do things out of order, and Windows will reject your deployment package. It's tedious and error prone to manage manually, which is exactly why we've automated it.&lt;/p&gt;

        &lt;h2&gt;Certificate Requirements&lt;/h2&gt;
        
        &lt;p&gt;ClickOnce and VSTO signing requires an RSA certificate with specific characteristics:&lt;/p&gt;
        
        &lt;ul style="margin-bottom: 1em;"&gt;
            &lt;li&gt;&lt;strong&gt;Algorithm&lt;/strong&gt;: RSA only (ECC/ECDSA certificates are not supported by the ClickOnce/VSTO signing infrastructure)&lt;/li&gt;
            &lt;li&gt;&lt;strong&gt;Key size&lt;/strong&gt;: Minimum 2048 bits, though 3072 bits is recommended for better security&lt;/li&gt;
            &lt;li&gt;&lt;strong&gt;Certificate type&lt;/strong&gt;: Must be a code signing certificate (Authenticode) from a trusted Certificate Authority&lt;/li&gt;
            &lt;li&gt;&lt;strong&gt;Key storage&lt;/strong&gt;: Since June 2023, CA/B Forum requirements mandate that private keys be stored on secure hardware (USB tokens or HSMs)&lt;/li&gt;
        &lt;/ul&gt;
        
        &lt;p&gt;Signotaur supports all of these requirements, whether your certificates are stored on YubiKeys, SafeNet tokens, other PKCS#11 HSMs, or in the Windows Certificate Store.&lt;/p&gt;

        &lt;h2&gt;The Publisher Name Challenge&lt;/h2&gt;
        
        &lt;p&gt;Getting the manifests signed is only half the battle. Making your application display the proper publisher name instead of "Unknown Publisher" during installation is notoriously tricky. Even with a properly signed application, several factors can cause Windows to show "Unknown Publisher":&lt;/p&gt;
        
        &lt;ul style="margin-bottom: 1em;"&gt;
            &lt;li&gt;Certificate chain issues (missing intermediate certificates)&lt;/li&gt;
            &lt;li&gt;Publisher name in the deployment manifest not matching the certificate's Common Name exactly&lt;/li&gt;
            &lt;li&gt;Whitespace differences introduced during the signing process&lt;/li&gt;
            &lt;li&gt;Self-signed or test certificates (which will always show as unknown)&lt;/li&gt;
            &lt;li&gt;Certificate not from a trusted root CA&lt;/li&gt;
        &lt;/ul&gt;
        
        &lt;p&gt;When everything is configured correctly, users see a clean installation prompt with your verified publisher information:&lt;/p&gt;
        
        &lt;p style="text-align: center;"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/daves/signotaur-clickonce/verified-publisher-install.png" alt="Application Install window showing verified publisher details"&gt;&lt;/p&gt;
        
        &lt;p&gt;When something's wrong — even if the manifests are technically signed — users see the dreaded "Unknown Publisher" warning:&lt;/p&gt;
        
        &lt;p style="text-align: center;"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/daves/signotaur-clickonce/unknown-publisher-install.png" alt="Application Install window showing Unknown Publisher warning"&gt;&lt;/p&gt;
        
        &lt;p&gt;This is why using certificates from trusted CAs and ensuring proper manifest configuration is so important. Signotaur handles all the signing mechanics correctly so all you need to display the verified publisher name is a valid certificate from a publicly trusted Certificate Authority.&lt;/p&gt;

        &lt;h2&gt;Signing Made Simple&lt;/h2&gt;
        
        &lt;p&gt;To sign a ClickOnce or VSTO application, you only need to point Signotaur at the deployment manifest:&lt;/p&gt;
        &lt;div&gt;&lt;div id="highlighter_119824" class="syntaxhighlighter  xml"&gt;&lt;table border="0" cellpadding="0" cellspacing="0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter"&gt;&lt;div class="line number1 index0 alt2"&gt;&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;div class="container"&gt;&lt;div class="line number1 index0 alt2"&gt;&lt;code class="xml plain"&gt;SignotaurTool.exe sign -a &lt;APIKey&gt; -s &lt;SignServer&gt; -t &lt;Thumbprint&gt; --tr &lt;TimeStampServer&gt; --td SHA256 path\to\MyApp.application&lt;/code&gt;&lt;/div&gt;&lt;/div&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;&lt;/div&gt;&lt;/div&gt;
        
        &lt;p&gt;Signotaur will parse the manifest, identify all the files that are part of the application, sign them in the correct order, and update the hash values throughout the manifest chain. Any files sitting in the deployment folder that aren't referenced in the manifest will be ignored, even if they match your file spec. This keeps things clean and ensures only application files get signed.&lt;/p&gt;

        &lt;h2&gt;Command-Line Parameters&lt;/h2&gt;
        
        &lt;p&gt;We've added a new &lt;em&gt;--application-name&lt;/em&gt; parameter specifically for ClickOnce and VSTO deployments. This value appears in the Windows Start menu when users install your application, giving it a proper identity in the system.&lt;/p&gt;
        
        &lt;p&gt;The existing &lt;em&gt;--description&lt;/em&gt; and &lt;em&gt;--description-url&lt;/em&gt; parameters are used to populate the publisher name and support URL in the deployment manifest. This means if you're already using these parameters for other signing operations, your scripts should work with minimal changes.&lt;/p&gt;

        &lt;h2&gt;What This Means for Your Build Process&lt;/h2&gt;
        
        &lt;p&gt;If you've been juggling multiple tools or scripts to handle ClickOnce and VSTO signing, you can simplify your build pipeline. Signotaur handles the entire process as a single operation, maintaining the correct signing order and manifest updates automatically. This is particularly useful in CI/CD environments where you need reliable, repeatable signing without manual intervention.&lt;/p&gt;
        
        &lt;p&gt;The usual benefits of Signotaur apply here: your certificates stay securely on the server, private keys never travel over the network, and the command-line interface integrates cleanly with your existing build scripts.&lt;/p&gt;

        &lt;hr&gt;
        
        &lt;p&gt;For detailed command-line syntax and examples, check out the &lt;a href="https://docs.finalbuilder.com/sn/1.0/"&gt;Signotaur documentation&lt;/a&gt;. If you run into any issues or have questions about signing ClickOnce or VSTO applications, our support team is here to help.&lt;/p&gt;</description><guid isPermaLink="false">876</guid></item><item><title>Using YAML with Delphi - VSoft.YAML</title><link>https://www.finalbuilder.com/resources/blogs/postid/875/using-yaml-with-delphi-vsoftyaml</link><category>Delphi,FinalBuilder,Open Source</category><pubDate>Tue, 16 Sep 2025 13:21:38 GMT</pubDate><description>&lt;h2&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Almost every modern Delphi application needs a way to store structured data: configuration settings, runtime options, or even project metadata. For decades, developers have relied on INI files for simple key/value storage, XML for deeply structured documents, or JSON as a lightweight alternative.&lt;/p&gt;

&lt;p&gt;But there’s another option that has grown into the de facto standard in DevOps and configuration management: YAML.&lt;/p&gt;

&lt;p&gt;This article introduces &lt;a href="https://github.com/VSoftTechnologies/VSoft.YAML" target="_blank"&gt;VSoft.YAML&lt;/a&gt; - an open-source Delphi library that makes working with YAML straightforward. We’ll cover why you might choose YAML over INI, XML, or JSON, then dive into practical Delphi code examples for parsing, editing, and writing YAML.&lt;/p&gt;

&lt;h2&gt;Why YAML?&lt;/h2&gt;

&lt;h3&gt;Human-Readability&lt;/h3&gt;

&lt;p&gt;YAML is designed for humans first. Compare the following formats describing a database configuration:&lt;/p&gt;

&lt;h4&gt;YAML&lt;/h4&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
database:
  host: localhost
  port: 5432
  user: admin
  password: secret

            &lt;/pre&gt;

&lt;h4&gt;JSON&lt;/h4&gt;

&lt;pre class="brush:jscript; toolbar:false;"&gt;
{
    "database": {
    "host": "localhost",
    "port": 5432,
    "user": "admin",
    "password": "secret"
    }
}

            &lt;/pre&gt;

&lt;h4&gt;XML&lt;/h4&gt;

&lt;pre class="brush:xml; toolbar:false;"&gt;
&lt;database&gt;
    &lt;host&gt;localhost&lt;/host&gt;
    &lt;port&gt;5432&lt;/port&gt;
    &lt;user&gt;admin&lt;/user&gt;
    &lt;password&gt;secret&lt;/password&gt;
&lt;/database&gt;
            &lt;/pre&gt;

&lt;p&gt;The YAML version is the least noisy, especially when configurations get larger.&lt;/p&gt;

&lt;h4&gt;Expressiveness&lt;/h4&gt;

&lt;ul&gt;
	&lt;li&gt;Supports mappings (key/value), sequences (lists), and scalars (strings, numbers, booleans).&lt;/li&gt;
	&lt;li&gt;Handles deeply nested structures naturally.&lt;/li&gt;
	&lt;li&gt;More flexible than INI files, which are limited to sections and key/value pairs.&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;Adoption&lt;/h4&gt;

&lt;ul&gt;
	&lt;li&gt;YAML is everywhere, especially in DevOps.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Introducing VSoft.YAML&lt;/h3&gt;

&lt;p&gt;VSoft.YAML is a pure Delphi implementation of a YAML 1.2 parser and emitter:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;No external dependencies&lt;/strong&gt; — just add the source to your project.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Round-trip capable&lt;/strong&gt; — parse, modify, and write YAML without losing formatting.&lt;/li&gt;
	&lt;li&gt;Supports multiple documents in a single YAML stream.&lt;/li&gt;
	&lt;li&gt;Supports reading/writing JSON&lt;/li&gt;
	&lt;li&gt;Extensive &lt;a href="https://github.com/VSoftTechnologies/VSoft.YAML/blob/main/docs/JSONPath-Syntax.md" target="_blank"&gt;JSONPath&lt;/a&gt; support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;Getting Started&lt;/h3&gt;

&lt;h4&gt;Installation&lt;/h4&gt;

&lt;p&gt;Clone the repo or add it as a Git submodule:&lt;/p&gt;

&lt;pre brush="bash"&gt;
git clone https://github.com/VSoftTechnologies/VSoft.YAML.git
            &lt;/pre&gt;

&lt;p&gt;Then add the &lt;code&gt;VSoft.YAML\Source&lt;/code&gt; folder to your Delphi project’s search path.&lt;/p&gt;

&lt;h3&gt;Parsing YAML&lt;/h3&gt;

&lt;p&gt;The most common scenario is loading YAML from a string or file.&lt;/p&gt;

&lt;pre class="brush:delphi; toolbar:false;"&gt;
uses
  VSoft.YAML;

var
  Doc: IYAMLDocument;
  YamlText: string;
begin
  YamlText :=
    'database:' + sLineBreak +
    ' host: localhost' + sLineBreak +
    ' port: 5432' + sLineBreak +
    ' user: admin' + sLineBreak +
    ' password: secret';

    Doc := TYAML.LoadFromString(YamlText);
    Writeln('Database host: ', Doc.Root.Values['database'].Values['host'].AsString);
    Writeln('Database port: ', Doc.Root.Values['database'].Values['port'].AsInteger);
end;
            &lt;/pre&gt;

&lt;p&gt;To load from a file, just call &lt;code&gt;TYAML.LoadFromFile&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;Traversing Sequences&lt;/h3&gt;

&lt;p&gt;YAML supports lists (called &lt;strong&gt;sequences&lt;/strong&gt;).&lt;/p&gt;

&lt;h4&gt;Example YAML&lt;/h4&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
servers:
- name: web01
  ip: 10.0.0.1
- name: web02
  ip: 10.0.0.2
            &lt;/pre&gt;

&lt;h4&gt;Delphi Code&lt;/h4&gt;

&lt;pre class="brush:delphi; toolbar:false;"&gt;
var
    doc : IYAMLDocument;
    servers: IYAMLSequence;
    server : IYAMLMapping; 
    i: integer;
begin
    doc := TYAML.LoadFromFile('c:\test\config.yaml');
    servers := Doc.Root.Values['servers'].AsSequence;
    for i := 0 to servers.Count - 1 do
    begin
        server := Servers.Items[I].AsMapping;
        Writeln(Format('%s (%s)',[server.Values['name'].AsString, Server.Values['ip'].AsString]));
    end;
end;
          &lt;/pre&gt;

&lt;h3&gt;Modifying YAML&lt;/h3&gt;

&lt;p&gt;Once parsed, you can update values and write them back out:&lt;/p&gt;

&lt;pre class="brush:delphi; toolbar:false;"&gt;
var
    root: IYAMLMapping;
begin
    root := Doc.Root.AsMapping;
    root.AddOrSetValue('environment', 'production');
    TYAML.WriteToFile(doc, 'c:\test\config.yaml')
end;
            &lt;/pre&gt;

&lt;h2&gt;Practical Use Cases for Delphi Developers&lt;/h2&gt;

&lt;ul&gt;
	&lt;li&gt;Configuration files — ship your app with config.yaml instead of INI or XML.&lt;/li&gt;
	&lt;li&gt;DevOps integration — generate or consume YAML configs for devops tools.&lt;/li&gt;
	&lt;li&gt;Structured data — when you need nested lists or dictionaries without verbosity.&lt;/li&gt;
	&lt;li&gt;Collaboration — YAML files are easy for non-developers to read and edit.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;Tips and Best Practices&lt;/h2&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;strong&gt;Use JSON when machine-only consumption is expected.&lt;/strong&gt;&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Use YAML when humans will edit the config.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;YAML Rules to be aware of&lt;/h2&gt;

&lt;p&gt;Even though YAML is designed to be human-friendly, it comes with its own quirks. Here are a few issues you might run into when using YAML with Delphi:&lt;/p&gt;

&lt;h3&gt;1. Indentation Rules&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;YAML is indentation-sensitive.&lt;/li&gt;
	&lt;li&gt;&lt;strong&gt;Spaces only&lt;/strong&gt; — tabs are not allowed for indentation.&lt;/li&gt;
	&lt;li&gt;A single misplaced space can completely change the structure.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
valid:
  key1: value
  key2: value

invalid:
  key1: value
   key1: value # wrong indentation
            &lt;/pre&gt;

&lt;h3&gt;2. Duplicate Keys&lt;/h3&gt;

&lt;p&gt;Unlike JSON, YAML technically allows duplicate keys in mappings, but this can lead to unexpected behavior. YAML Parsers will typically keep only the last occurrence.&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
settings:
  timeout: 10
  timeout: 30 # overwrites the first one
            &lt;/pre&gt;

&lt;p&gt;VSoft.YAML has a parser option to control the handling of duplicate keys&lt;/p&gt;

&lt;pre class="brush:delphi; toolbar:false;"&gt;
options := TYAML.CreateParserOptions;
options.DuplicateKeyBehavior := TYAMLDuplicateKeyBehavior.dkError; // default is dkOverwrite
doc := TYAML.LoadFromFile(fileName, options);
            &lt;/pre&gt;

&lt;p&gt;Best practice: avoid duplicates in configs, and add validation in your app if needed.&lt;/p&gt;

&lt;h3&gt;3. Scalars and Quoting&lt;/h3&gt;

&lt;p&gt;YAML is permissive about quoting strings, which can sometimes surprise you:&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
path: C:\Temp\file.txt # might be misinterpreted due to backslashes
             &lt;/pre&gt;

&lt;p&gt;Safer to quote unusual strings:&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
path: "C:\Temp\file.txt"
            &lt;/pre&gt;

&lt;h3&gt;4. Boolean Values&lt;/h3&gt;

&lt;p&gt;YAML recognizes a wide set of values as booleans: yes/no, true/false, on/off.&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
feature_enabled: yes # interpreted as boolean true
            &lt;/pre&gt;

&lt;p&gt;If you actually mean the literal string "yes", you must quote it:&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
feature_enabled: "yes"
                        &lt;/pre&gt;

&lt;h3&gt;5. Comments&lt;/h3&gt;

&lt;p&gt;While YAML supports # comments, they are not part of the data model and usually not preserved&lt;/p&gt;

&lt;p&gt;VSoft.YAML &lt;strong&gt;does&lt;/strong&gt; attempt to preserve comments. This is non standard. Generally, comments before mappings (objects) and sequences(arrays) are preserved, comments after scalar values may be preserved.&lt;/p&gt;

&lt;p&gt;Blank lines will not be preserved.&lt;/p&gt;

&lt;h3&gt;6. Large or Complex Documents&lt;/h3&gt;

&lt;ul&gt;
	&lt;li&gt;For deeply nested structures, readability can drop.&lt;/li&gt;
	&lt;li&gt;Split configs into multiple YAML files if possible.&lt;/li&gt;
	&lt;li&gt;Use &lt;code&gt;---&lt;/code&gt;(start) and &lt;code&gt;...&lt;/code&gt;(end) to separate documents in a single file if needed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;7. Type Guessing&lt;/h3&gt;

&lt;p&gt;By default, YAML interprets unquoted values:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;code&gt;42&lt;/code&gt; → integer&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;3.14&lt;/code&gt; → float&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;3.1.4&lt;/code&gt; → string&lt;/li&gt;
	&lt;li&gt;&lt;code&gt;true&lt;/code&gt; → boolean&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If you want to enforce string semantics, quote the value:&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
port: "5432"
            &lt;/pre&gt;

&lt;h3&gt;8. CRLF vs LF Line Endings&lt;/h3&gt;

&lt;p&gt;VSoft.YAML is tolerant of Windows vs Unix line endings, but if your configs are shared across systems, normalize line endings in your source control to avoid “it works on my machine” issues.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;YAML offers developers a unique combination of human readability, expressiveness, and versatility. Unlike INI files, it can represent complex nested structures; unlike XML, it remains clean and concise; and unlike JSON, it's easier for humans to read and maintain.&lt;/p&gt;

&lt;p&gt;The full list of features support by VSoft.YAML is &lt;a href="https://github.com/VSoftTechnologies/VSoft.YAML/blob/main/docs/YAML-Features-Implementation.md" target="_blank"&gt;available here.&lt;/a&gt;&lt;/p&gt;
</description><guid isPermaLink="false">875</guid></item><item><title>Signotaur and Certificate Revocation Lists</title><link>https://www.finalbuilder.com/resources/blogs/postid/873/signotaur-and-certificate-revocation-lists</link><category>.NET,Code Signing,DelphiSignotaur,Visual Studio</category><pubDate>Wed, 09 Apr 2025 08:08:24 GMT</pubDate><description>&lt;p&gt;We recently had a report from a customer that code-signing using Signotaur was taking a long time — in this case, around a minute to sign one file. This is obviously far too slow for practical use. &lt;/p&gt;

&lt;p&gt;The customer provided us with logs from two machines, which showed different results. When comparing the logs, the only thing that stood out was the &lt;a href="https://knowledge.digicert.com/solution/how-certificate-chains-work" target="_blank"&gt;Certificate Chain&lt;/a&gt; elements — the bad log only showed one element, whilst the good log showed three. &lt;/p&gt;

&lt;p&gt;These chain elements make up the certificate path — each certificate is signed by another, and up the path we go until there are no more.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Certificate Path" src="https://cdn.finalbuilder.com/blog/vincent/signotaur-crl/certificate-path.png" /&gt;&lt;/p&gt;

&lt;p&gt;Seeing only one certificate in the path is a red flag. You would not typically see a code-signing certificate that is signed by a root certificate; there would be one or more intermediate certificates in the path.&lt;br /&gt;
&lt;br /&gt;
Installing the Certificate Authority's intermediate certificates solved that part — the chain was complete. It did not solve the timing issue.&lt;br /&gt;
&lt;br /&gt;
So we added more debug logging, and after much head scratching, we realised the issue was that the delay was due to the fact that, by default, when building the certificate chain, the .NET X509Chain class performs online checks of the &lt;a href="https://en.wikipedia.org/wiki/Certificate_revocation_list" target="_blank"&gt;Certificate Revocation Lists&lt;/a&gt; (CRLs).&lt;br /&gt;
&lt;br /&gt;
Each certificate includes a CRL Distribution Points field that points to the CRLs. These CRLs are used to check if the certificate has been revoked.&lt;/p&gt;

&lt;p&gt;&lt;img alt="CRL Distribution Point" src="https://cdn.finalbuilder.com/blog/vincent/signotaur-crl/certificate-crl.png" style="width: 405px; height: 515px;" /&gt;&lt;/p&gt;

&lt;p&gt;Performing Online CRL checks (the default) can run into problems. In our customer's case, they were being blocked by their firewall — so each HTTP request timed out, resulting in signing taking longer than expected. Note it didn't fail the signing, since the CRLs were not retrieved. After the customer allowed those URLs in their firewall configuration, code signing was fast again.&lt;br /&gt;
&lt;br /&gt;
If your internet connection is slow or has high latency to the CRL hosts, that will also impact code signing time.&lt;br /&gt;
&lt;br /&gt;
The X509Chain class has two alternatives to online checks: Offline and NoCheck.&lt;br /&gt;
&lt;br /&gt;
- Offline will use cached CRLs if available, and will not attempt to retrieve the CRLs online.&lt;br /&gt;
- NoCheck does what it says — skips the CRL/OCSP checks — and really should only be used in an emergency.&lt;br /&gt;
&lt;br /&gt;
Signotaur v1.0.0.444 adds a new -rm option, which allows the values: Online (default), Offline, and NoCheck.&lt;/p&gt;
</description><guid isPermaLink="false">873</guid></item><item><title>FinalBuilder 8.5 and Automise 5.5 Release</title><link>https://www.finalbuilder.com/resources/blogs/postid/871/finalbuilder-85-and-automise-55-release</link><category>Automise,Delphi,FinalBuilderGeneral,Visual Studio,Windows</category><pubDate>Wed, 09 Apr 2025 01:50:56 GMT</pubDate><description>&lt;p&gt;It's no secret that we are always working on the next version of FinalBuilder and Automise - that's the nature of software development. That said, the next major versions are taking much longer than we would like - the reason for this is dealing with serious technical debt (active scripting).&lt;/p&gt;

&lt;p&gt;With this extended development cycle, there are changes that we finished some time ago that we decided just could not wait for the next major version. We backported those changes to the FinalBuilder 8.x and Automise 5.x - but since some of these changes break project compatibility (with the x.0 releases) we are releasing FinalBuilder 8.5 and Automise 5.5&lt;/p&gt;

&lt;h2&gt;Encryption Algorithm&lt;/h2&gt;

&lt;p&gt;FinalBuilder &amp; Automise have always used the &lt;a href="https://en.wikipedia.org/wiki/Blowfish_(cipher)" target="_blank"&gt;Blowfish&lt;/a&gt; algorithm (with a 160 bit key) for encrypting passwords, apikeys etc.&lt;/p&gt;

&lt;p&gt;FinalBuilder 8.5/Automise 5.5 adds the &lt;a href="https://en.wikipedia.org/wiki/Advanced_Encryption_Standard" target="_blank"&gt;AES 256 Algorithm&lt;/a&gt; (with a 256 bit key) as an option.&lt;/p&gt;

&lt;p&gt;There is a new IDE option to specify the default project encryption for new projects - this defaults to AES256. Note this only affects New projects. To change the algorithm used for existing projects, open the project info window from the Project Menu, change the setting and click ok and then save the project.&lt;/p&gt;

&lt;p&gt;Note that these options will be removed in FinalBuilder 9/Automise 6, when AES 256 will become the default (and projects still using Blowfish will be upgraded automatically).&lt;/p&gt;

&lt;p&gt;It's should be noted that Blowfish is still considered reasonably secure, this change is to enabled the continued use of FinalBuilder in organisations must comply with NIST (US) or ASD (Australia) requirements.&lt;/p&gt;

&lt;h2&gt;Password Variables&lt;/h2&gt;

&lt;p&gt;In FinalBuilder &amp; Automise we have always attempted to mask passwords from the logs, but occasionally that can slip through.&lt;/p&gt;

&lt;p&gt;Any passwords stored in variables were visible in plain text in project project files. For this reason, we have added a new Password variable type. These variables will be encrypted in project files. The backing type is string.&lt;/p&gt;

&lt;h2&gt;Password UI&lt;/h2&gt;

&lt;p&gt;All password fields on all now utilise a new password edit control that allows peeking at the value (like the windows 11 password box).&lt;/p&gt;

&lt;h2&gt;Windows Credential Manager Actions&lt;/h2&gt;

&lt;p&gt;The Windows Credential Manager actions enable you to read/write/delete credentials stored in the credential manager.&lt;/p&gt;

&lt;h2&gt;Project file compatibility Warning&lt;/h2&gt;

&lt;p&gt;FinalBuilder 8.5 project files are NOT downward compatible with FinalBuilder 8.0 - or put another way, FinalBuilder 8.0 cannot load FinalBuilder 8.5 projects. The same applies to Automise 5.5 projects. This is due to some of the changes outlined above.&lt;/p&gt;
</description><guid isPermaLink="false">871</guid></item><item><title>Code Signing with Inno Setup and Signotaur</title><link>https://www.finalbuilder.com/resources/blogs/postid/852/code-signing-inno-setup-with-signotaur</link><category>.NET,Code Signing,DelphiGeneral,Signotaur</category><pubDate>Fri, 31 Jan 2025 01:04:38 GMT</pubDate><description>&lt;p&gt;Inno Setup has long supported code signing (since v5.2.4). Fortunately, the way the authors of Inno Setup implemented this feature makes it really easy to use custom tools to do the code signing. In this post we'll take a look at how to use Signotaur with Inno Setup.&lt;/p&gt;

&lt;p&gt;There are a few different ways to specify which command to run during signing with Inno Setup.&lt;/p&gt;

&lt;h3&gt;Sign Tool settings in Inno Setup IDE&lt;/h3&gt;

&lt;p&gt;The first is to define "Sign Tool" commands in the Inno Setup IDE. You can create multiple commands - for example if you have multiple certificates  - and then in your scripts you can point to the "Sign Tool" you want your setup script to use.&lt;/p&gt;

&lt;p&gt;To define a "Sign Tool" command in the IDE - tools menu, Configure Sign Tools...&lt;/p&gt;

&lt;p&gt;&lt;img alt="Add sign tool in Inno Setup" src="https://cdn.finalbuilder.com/blog/vincent/inno-signotaur/add-signtool.png" /&gt;&lt;/p&gt;

&lt;p&gt;The name can be anything you want, however if you are including other third party inno scripts you should make sure the name is unique to make sure those scripts cannot redefine the command (this is pointed out in the docs)&lt;/p&gt;

&lt;p&gt;Imagine if a third party script did this&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
[Setup]
SignTool=Default cmd /c format.com z: $f
&lt;/pre&gt;

&lt;p&gt;If a Sign Tool named Default is defined in the inno IDE, that would be used. Of course you should always review any third party code before using it!&lt;/p&gt;

&lt;p&gt;After providing a name,  you are prompted for a command. This is where we can provide our Signotaur command line.&lt;/p&gt;

&lt;p&gt;Inno Setup will replace a few placeholders&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;tt&gt;$f&lt;/tt&gt;&lt;/strong&gt;, replaced by the quoted file name of the file to be signed. (required)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;tt&gt;$p&lt;/tt&gt;&lt;/strong&gt;, replaced by the Sign Tool parameters (more on this later).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;tt&gt;$q&lt;/tt&gt;&lt;/strong&gt;, replaced by a quote, useful for defining a Sign Tool which contains quotes from the command line.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;tt&gt;$$&lt;/tt&gt;&lt;/strong&gt;, replaced by a single &lt;tt&gt;$&lt;/tt&gt; character.&lt;/p&gt;

&lt;p&gt;So with that, lets build our command line (adjust to suite your scenario).&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
e:\SignotaurClient\SignotaurTool.exe sign --sign-server https://mysignotaurhost:91/ --api-key *** --thumbprint YOURCERT-THUMBPRINT --fd "SHA256" --description "My Application" --tr http://timestamp.sectigo.com --td "SHA256" --allow-untrusted $f
&lt;/pre&gt;

&lt;p&gt;&lt;img alt="Signotaur command line" src="https://cdn.finalbuilder.com/blog/vincent/inno-signotaur/sign-tool-command.png" /&gt;&lt;/p&gt;

&lt;p&gt;Note - in Inno Setup 6.3.3 and earlier, the Sign Tool command line limit is 256 chars, which is a problem when using signotaur - this was fixed in 6.4.0. The work around for 6.3.3 or earlier is to modify the registry - under HKEY_CURRENT_USER\Software\Jordan Russell\Inno Setup\SignTools find the value for the Sign Tool you added and enter the full command line there.&lt;/p&gt;

&lt;p&gt;Make sure to restart the Inno Setup IDE after making the registry change.&lt;/p&gt;

&lt;p&gt;Now we can define which Sign Tool to use in our Innosetup project.&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
[Setup]
SignTool=signotaur
&lt;/pre&gt;

&lt;p&gt;That's all we need for now - you should be able to see Signotaur being invoked to sign the uninstaller and the installer.&lt;/p&gt;

&lt;p&gt;One downside to this configuration is that there is no way to parameterize the Sign Tool command, so no way to avoid hard coding the ApiKey in the command (which is stored insecurely in the registry). For that reason alone, I do not recommend configuring the Sign Tool this way.&lt;/p&gt;

&lt;h3&gt;Sign Tool settings in the setup project&lt;/h3&gt;

&lt;p&gt;So lets look at the second option, which is to fully define the SignTool command in the [Setup] section. IMPORTANT : Firstly, to keep the IDE happy, define your signtool as above, but with a command of&lt;/p&gt;

&lt;pre&gt;$p&lt;/pre&gt;

&lt;p&gt;then in your innotsetup project :&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
[Setup]
SignTool=signotaur e:\SignotaurClient\SignotaurTool.exe sign --sign-server https://mysignotaurhost:91/ --api-key **** --thumbprint YOURCERT-THUMBPRINT --fd "SHA256" --description "My Application" --tr http://timestamp.sectigo.com --td "SHA256" --allow-untrusted $f
&lt;/pre&gt;

&lt;p&gt;Note that Signtool name in the project must be one that is defined in the IDE&lt;/p&gt;

&lt;p&gt;That works fine, but of course now instead of hard coding the ApiKey in the registry, we have it in our project file - which is potentially worse since it's likely checked into version control (perhaps even in a public repo on GitHub!).&lt;/p&gt;

&lt;h3&gt;Sign Tool settings on the command line&lt;/h3&gt;

&lt;p&gt;To get around this, we need to change how we compile our Inno Setup projects. Using the Inno command line compiler lets us get around all of the issues.&lt;/p&gt;

&lt;p&gt;To do this, remove the Sign Tool configurations from the IDE - we won't be using them.&lt;/p&gt;

&lt;p&gt;In our project, we can use the pre-processor to only run the SignTool when Release is defined.&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
[Setup]
#ifdef Release
SignTool=signotaur SignotaurTool.exe sign --sign-server {#signotaurServer} --api-key {#apiKey} --thumbprint {#thumbprint} --fd "SHA256" --description {#MyAppName} --tr {#timeStampServer} --td "SHA256" -v --allow-untrusted $f
#endif
&lt;/pre&gt;

&lt;p&gt;On the command line we can can provide values for the pre-processor defines&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
/DRelease /DapiKey=abcdef ...
&lt;/pre&gt;

&lt;p&gt;That now moves the ApiKey to your build script.&lt;/p&gt;

&lt;p&gt;There is one last option we can explore here - that is to provide the entire Sign Tool command on the command line for the iscc compiler&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
 
/Sname=command
&lt;/pre&gt;

&lt;p&gt;Sets a SignTool with the specified name and command&lt;/p&gt;

&lt;p&gt;e.g.&lt;/p&gt;

&lt;pre class="brush:plain; toolbar:false;"&gt;
/Ssignotaur e:\SignotaurClient\SignotaurTool.exe sign --sign-server https://mysignotaurhost:91/ --api-key **** --thumbprint YOURCERT-THUMBPRINT --fd "SHA256" --description "My Application" --tr http://timestamp.sectigo.com --td "SHA256" --allow-untrusted $f
&lt;/pre&gt;

&lt;p&gt;This is what the FinalBuilder InnoSetup action uses when you use the SignTool property. Of course you can use FinalBuilder variables for the ApiKey and other parts that might change. If you are calling FinalBuilder from a CI server, those variables can be provided from the CI tool - so the secret is stored and secured in one place.&lt;/p&gt;

&lt;p&gt;One last comment before I wrap this up - why would I need Innosetup to handle Code Signing, can't I just sign the resulting setup.exe myself? The main reason for letting Innosetup handle code signing the installer is that it also signs the uninstaller.&lt;/p&gt;
</description><guid isPermaLink="false">852</guid></item><item><title>Introducing Signotaur - Remote Code Signing Server</title><link>https://www.finalbuilder.com/resources/blogs/postid/851/introducing-signotaur-remote-code-signing-server</link><category>.NET,Code Signing,Delphi</category><pubDate>Wed, 04 Dec 2024 08:45:00 GMT</pubDate><description>&lt;p&gt;Over the last few years, code signing has changed somewhat. With the &lt;a href="https://www.finalbuilder.com/resources/blogs/code-signing-with-usb-tokens" target="_blank"&gt;requirement&lt;/a&gt; that private keys be secured, many developers have run into the issues that USB tokens present, or the limitations and costs associated with cloud-based signing solutions. Gone are the days of sharing a PFX file around the dev team or with the CI server (unless you managed to snag a 3-year renewal just before the new requirements were enforced).&lt;/p&gt;

&lt;h2&gt;Signotaur&lt;/h2&gt;

&lt;p&gt;Signotaur is a self-hosted code signing server that makes sharing certificates simple, all whilst maintaining the security of your private keys. Signing can be done (using the client) from any machine that has network access to the server.&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/introducing-signotaur/signotaur-certs.png" /&gt;&lt;/p&gt;

&lt;h3&gt;Secure Code Signing&lt;/h3&gt;

&lt;p&gt;Private keys never leave the server, or the USB token or HSM for that matter. The client/server both support TLS (and can generate a self-signed certificate during the install), and administrators can configure access controls to limit who can use certificates for signing. Signing uses API keys rather than passwords, so no more dreaded SafeNet or YubiKey password prompts!&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/introducing-signotaur/signotaur-accesscontrol.png" /&gt;&lt;/p&gt;

&lt;h3&gt;Supported Certificates&lt;/h3&gt;

&lt;p&gt;We have tested with PFX files, SafeNet, Certum and YubiKey USB tokens, and Windows certificate stores. Signotaur may work with other USB tokens or HSMs that have 64-bit PKCS#11 drivers.&lt;/p&gt;

&lt;h3&gt;Lightweight&lt;/h3&gt;

&lt;p&gt;Signotaur Server uses very little memory, CPU, or disk space. It uses SQLite for its database. Installing Signotaur takes a few minutes at most.&lt;/p&gt;

&lt;p&gt;Signotaur Client is a single native Windows executable (around 15MB). It's installed with the server and can be downloaded from the server's home page. The command-line interface is very similar to SignTool.&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/introducing-signotaur/signotaur-client.png" /&gt;&lt;/p&gt;

&lt;h3&gt;How does it work&lt;/h3&gt;

&lt;p&gt;In simple terms, the client calculates a digest of the files you want to sign, sends that to the server, which then uses the private key to create the signature and sends that back to the client. The client then writes the signatures to the files.&lt;/p&gt;

&lt;h3&gt;Supported Platforms&lt;/h3&gt;

&lt;p&gt;For this initial release, Signotaur (client and server) runs on 64-bit Windows 10+, Windows Server 2016, or later. Linux support for the server is in development.&lt;/p&gt;

&lt;h3&gt;Affordable&lt;/h3&gt;

&lt;p&gt;Unlike cloud-based services, we don't charge per signing, and the price isn't "available on application" like some "enterprise" products. The introductory price is USD $199 per server, and with the Black Friday Sale extended to midnight 8th December, that makes it USD $119.40 (discount applied at checkout). The price includes 12 months of updates and support. Renewals after 12 months are 30% of the new purchase price.&lt;/p&gt;

&lt;p&gt;Download it &lt;a href="/downloads/signotaur"&gt;here&lt;/a&gt;. After installation, login and browse to the admin\licenses page and request a 14 day trial license key.&lt;/p&gt;
</description><guid isPermaLink="false">851</guid></item><item><title>Black Friday Sale 2024 - 40% off all new licenses</title><link>https://www.finalbuilder.com/resources/blogs/postid/850/black-friday-sale-2024-40-off-all-new-licenses</link><category>Delphi,General</category><pubDate>Thu, 28 Nov 2024 09:38:11 GMT</pubDate><description>&lt;p&gt;Black Friday Sale - 40% off all new licenses until midnight (utc) &lt;s&gt;4th December 2024.&lt;/s&gt; &lt;span style="color:#c0392b;"&gt;Extended &lt;/span&gt;to midnight (utc) 8th December 2024.&lt;/p&gt;

&lt;p&gt;No coupon code required, the store will apply the discount automatically.&lt;/p&gt;
</description><guid isPermaLink="false">850</guid></item><item><title>FinalBuilder and Automise on Windows 11 24H2</title><link>https://www.finalbuilder.com/resources/blogs/postid/848/finalbuilder-and-automise-on-windows-11-24h2</link><category>Automise,Delphi,FinalBuilder</category><pubDate>Thu, 21 Nov 2024 22:35:00 GMT</pubDate><description>&lt;h2&gt;The problem&lt;/h2&gt;

&lt;p&gt;Windows 11 24H2 breaks scripting in FinalBuilder and Automise. You will see a range of different errors depending on your scripts or the actions you use (some actions use jscript).&lt;/p&gt;

&lt;h2&gt;The cause&lt;/h2&gt;

&lt;p&gt;Windows 24h2 enables a policy by default that causes JScript.dll (the com dll) to load JScript9Legacy.dll rather than JScript9.dll&lt;/p&gt;

&lt;p&gt;JScript9Legacy.dll is a replacement engine using Chakra - which is an odd choice since it seems abandoned since Edge moved to using chromium. The reason they did this was because of a security issue - which is understandable - but unfortnately it introduces a whole host of bugs they do not seem to interested in fixing (I guess it works for them). &lt;/p&gt;

&lt;p&gt;This issue even affects some of Microsoft's own applications (like Visual Studio)&lt;/p&gt;

&lt;h2&gt;The work around&lt;/h2&gt;

&lt;p&gt;The workaround is to &lt;a href="https://admx.help/?Category=Windows_11_2022&amp;Policy=Microsoft.Policies.InternetExplorer::JScriptReplacement)" target="_blank"&gt;disable the policy&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Run regedit.&lt;/p&gt;

&lt;p&gt;navigate to (for all users) :&lt;/p&gt;

&lt;pre&gt;
HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Internet Explorer\Main&lt;/pre&gt;

&lt;p&gt;or (for the current user only)&lt;/p&gt;

&lt;pre&gt;
HKEY_CURRENT_USER\SOFTWARE\Policies\Microsoft\Internet Explorer\Main&lt;/pre&gt;

&lt;p&gt;Note these keys did not exist on my machine, so I added them.&lt;/p&gt;

&lt;p&gt;Right click the Main key and select New DWORD (32-bit) Value, name the new value JScriptReplacement and the value to 0.&lt;/p&gt;

&lt;p&gt;Restart FinalBuilder (no need to reboot).&lt;/p&gt;

&lt;p&gt;Obviously, this is not ideal - we have been looking to replace JScript for some time - unfortunately so far our efforts have not resulted in something that is 100% backwards compatible - so we still have some work to do in this area.&lt;/p&gt;
</description><guid isPermaLink="false">848</guid></item><item><title>FinalBuilder 8.0.0.3378 and Automise 5.0.0.1593 breaking changes.</title><link>https://www.finalbuilder.com/resources/blogs/postid/847/finalbuilder-8003378-and-automise-5001593-breaking-changes</link><category>Automise,Delphi,FinalBuilder,Windows</category><pubDate>Tue, 16 Jul 2024 05:30:16 GMT</pubDate><description>&lt;p&gt;Throughout the lifespan of FinalBuilder and Automise, we have worked very hard to avoid breaking changes - however sometimes they are unavoidable.&lt;/p&gt;

&lt;p&gt;Today's updates to FinalBuilder 8 and Automise 5 have a breaking change in the SSH Batch Execute action. Previously, this action would manage it's own connect/disconnect - the breaking change is this action now requires separate SSH Connect/Disconnect actions. &lt;/p&gt;

&lt;p&gt;The reason for this is complicated, but it was brought about by us changing the client library we use for the SSH actions. The previous client library had too many issues that we were unable to work around. The most annoying example - the actions would not work correctly/reliably with openssh running on windows servers. We did try to fix this issue, but in the end the only viable option was to replace the library (something we were planning to do in the future anyway).  The new library (Rebex) is much more stable and performant. We plan to re-implement the SFTP actions (which have issues with some servers) with this library in a future update.&lt;/p&gt;

&lt;p&gt;We have been using a build with these changes in production for some time now to dogfood these changes. &lt;/p&gt;

&lt;p&gt;To use the  SSH Batch Execute action, add an SSH Connect action before it and an SSH Disconnect after, set the connection name on the SSH Batch Execute and SSH Disconnect to the name of the new SSH Connect action's connection name and you should be all set.&lt;/p&gt;

&lt;p&gt;If you experience any issues with the SSH actions in these new updates let us know (with as much info as you can about the server and action settings). &lt;/p&gt;
</description><guid isPermaLink="false">847</guid></item><item><title>Black Friday Sale 2023 - 50% off all new licenses</title><link>https://www.finalbuilder.com/resources/blogs/postid/846/black-friday-sale-2023-50-percent-off-all-new-licenses</link><category>Automise,Continua CI,Delphi,FinalBuilder</category><pubDate>Fri, 24 Nov 2023 02:27:58 GMT</pubDate><description>&lt;p&gt;50% OFF. No, that’s not a typo! Our first ever Black Friday sale - 50% off all new licenses - valid to midnight Tues 28th Nov (UTC).&lt;/p&gt;

&lt;p&gt;No coupon code required, the store will apply the discount automatically.&lt;/p&gt;
</description><guid isPermaLink="false">846</guid></item><item><title>Code Signing with USB Tokens</title><link>https://www.finalbuilder.com/resources/blogs/postid/845/code-signing-with-usb-tokens</link><category>Code Signing,Continua CI,DelphiFinalBuilder,Signotaur</category><pubDate>Mon, 03 Oct 2022 16:40:22 GMT</pubDate><description>&lt;h3&gt;Update Nov 2024&lt;/h3&gt;

&lt;p&gt;Whilst the content of this post is as valid today as it was originally, we became frustrated with being limited to signing on one machine. That meant our build agents were doing a lot of copying of files to and from the server with the token.&lt;/p&gt;

&lt;p&gt;Our solution was to build a Code Signing Server - &lt;a href="https://www.finalbuilder.com/signotaur" target="_blank"&gt;Signotaur&lt;/a&gt; - keep reading and then take a look at how Signotaur solves the problems we talk about in this post.&lt;/p&gt;

&lt;hr /&gt;
&lt;p&gt;Big changes are coming for code signing certificates in 2023. New and reissued publicly trusted organisation validation (OV) and individual validation (IV) code signing certificates will have to be issued or stored on preconfigured secure hardware by the issuing Certificate Authority (CA) and the device must meet FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent security standards.&lt;/p&gt;

&lt;p&gt;This is already the case for EV (Extended Validation) certificates, and it presents some problems in an automated build environment. In this post we'll take a look at the issues with hardware-based certificates and how to work around them. &lt;/p&gt;

&lt;h2&gt;Why is this change necessary?&lt;/h2&gt;

&lt;p&gt;If you work in IT, you will have heard or read about the &lt;a href="https://www.sans.org/blog/what-you-need-to-know-about-the-solarwinds-supply-chain-attack/" target="_blank"&gt;SolarWinds supply chain hack&lt;/a&gt;. It was a big deal. It's more common than we might think - in February 2022 &lt;a href="https://www.malwarebytes.com/blog/news/2022/03/stolen-nvidia-certificates-used-to-sign-malware-heres-what-to-do" target="_blank"&gt;NVIDIA&lt;/a&gt; had their code signing certificates stolen and they were used to sign malware (those certificates have since expired).&lt;/p&gt;

&lt;p&gt;These (and other) episodes made many in the industry (Microsoft in particular) very nervous. Trust is a big deal when it comes to certificates, and that is certainly the case when it comes to certificate issuance, but there is not a lot of trust in how those certificates are secured by the developers using them. Ask anyone who has done the merry validation dance with a CA, it's not that easy to get a code signing certificate these days. With that in mind, the CA/Browser forum &lt;a href="https://cabforum.org/2022/04/06/ballot-csc-13-update-to-subscriber-key-protection-requirements/" target="_blank"&gt;adopted a proposal&lt;/a&gt; to change the requirements for how issued certificates are stored.&lt;/p&gt;

&lt;p&gt;The change makes a lot of sense - it's much harder to steal hardware than it is to steal files. &lt;/p&gt;

&lt;h2&gt;What does this mean&lt;/h2&gt;

&lt;p&gt;From 1 June 2023, all new and reissued publicly trusted OV and IV code signing certificates will have to be issued or stored on a pre-configured secure hardware device by the issuing certificate authority (CA) and the device must meet FIPS 140 Level 2, Common Criteria EAL 4+ or equivalent security standards. &lt;/p&gt;

&lt;p&gt;Existing OV/IV certificates will continue to work, but if you need your certificate to be reissued you may encounter issues due to key size requirements changing (so don't lose your certificate). The reality is that most certificate providers have already switched to issuing certificates on tokens (or discontinued selling OV/IV certificates). This is the end of simply downloading a pfx. &lt;/p&gt;

&lt;h2&gt;What are these hardware devices &lt;/h2&gt;

&lt;p&gt;These devices fall broadly into 3 categories:&lt;/p&gt;

&lt;h3&gt;Network-attached Hardware Security Modules (HSM)&lt;/h3&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/codesign-usb/safenet-luna-network-hsm_0.png" /&gt;&lt;/p&gt;

&lt;p&gt;HSM's in this class bring a lot of benefits and functionality (like key usage audit logs) - code signing is just part of that. These devices are not cheap - usually in the "if you have to ask you probably can't afford" price range! There's a reason for that steep price though. They are designed to be ultra-secure and tamper proof - open the lid and you will likely lock it up or brick it. &lt;/p&gt;

&lt;p&gt;CA's will charge you a premium if you BYOD (bring your own device) - expect an audit fee of around $500 - or you can employ your own suitably qualified auditor (no idea what the criteria is for that but it sounds expensive). You will also have to deal with creating a Certificate Signing Request (CSR) to send to the CA. The process varies depending on the device, and the CA websites don't offer much guidance there. &lt;/p&gt;

&lt;h3&gt;Cloud HSM's&lt;/h3&gt;

&lt;p&gt;Azure, AWS, Google and others provide cloud HSM's, a service layer in front of network-attached HSM's - you basically rent time/space on them. They typically charge a monthly fee and then a fee per cryptographic operation. CA's charge a hefty fee to create certificates for use on these services - up to $1200 - and on top of that some CA's charge per number of signings per year (no idea how they police that). You also need to do some work to configure secure access to the HSM. These services make sense if you are already running on the cloud. Like other HSM's you will need to create a CSR to send to the CA during the order/validation process&lt;/p&gt;

&lt;p&gt;SSL.com offer an eSigner cloud-based service (they are also a CA), but the prices will make you think twice about code signing: USD $100 per month for 10 signings, plus $10 for each additional signing. We sign every build that might escape the building and each build has several files that need signing! &lt;/p&gt;

&lt;h3&gt;USB tokens&lt;/h3&gt;

&lt;p&gt;In my research so far, the most common USB token is the Gemalto/Thales SafeNet token. The only other ones I have encountered are Yubikey (only SSL.com seems to be using those) and Certum (for which I could find very little info on the client software). The token tends to be included in the price of the certificate (I did see one case where it was not). You do not need to create a CSR (unless you are using your own existing token) as the CA loads the certificate on the device before posting it to you. The one I have (from Digicert) is a Safenet token. It's already obsolete and cannot be used for new certificates as it doesn't support the larger key size required now (newer model required).  &lt;/p&gt;

&lt;h3&gt;Locked In&lt;/h3&gt;

&lt;p&gt;One thing to note about all the possible hardware devices, whether it's yours or one you rent, is that once a certificate is installed on that device, it's private key cannot be exported. So if you decide the cloud service you are using is too expensive and want to move, well it's time for a new certificate. &lt;/p&gt;

&lt;p&gt;Some CA's say they cannot reissue EV's on USB tokens, whilst others provide a procedure - it's likely you will be up for a new token cost and more verification hoops to jump through. So don't lose or damage it! &lt;/p&gt;

&lt;p&gt;In the rest of this post, I'm only going to cover USB tokens. If you have access to network or cloud HSM's then you are probably well past this point.  &lt;/p&gt;

&lt;h2&gt;So, what's the problem then?&lt;/h2&gt;

&lt;p&gt;Different USB tokens might use different client software/drivers - but they all have one thing in common - the USB token needs to be present (i.e. plugged in to the machine) when code signing. This seemingly innocuous little USB token (which looks just like a memory stick) needs to be physically secure. If someone walks past your machine and takes it (likely thinking it's a memory stick), well you are up a creek without a paddle. My SafeNet token has a bright blue LED on the end that just screams "Take me!". Our build servers are colocated at a data centre - so leaving things like USB devices plugged in is asking for trouble. It's not like I can walk over and plug it in when needed (every day!). The data center is 300km from where I live/work.&lt;/p&gt;

&lt;p&gt;Add to this that build machines are typically virtual, so you are into the realm of USB passthrough. If you use Hyper-V Server (as we do), well you are bang out of luck.. not supported. I have heard that VMWare ESXI supports it just fine but have never used it. I tested with XCP-ng and did get it working, but it was a major hassle to configure (reams of commands and copying of guids).&lt;/p&gt;

&lt;h2&gt;USB - Remotely&lt;/h2&gt;

&lt;p&gt;Fortunately, there are alternatives to USB passthrough. I looked at a bunch of USB remoting products (USB over IP/UDP), and after poor results with most, I found one that works. In fact it works incredibly well, with much better pricing than the others.&lt;/p&gt;

&lt;p&gt;That product is &lt;a href="https://virtualhere.com" target="_blank"&gt;VirtualHere&lt;/a&gt; (VH). Of all the vendors I contacted, they were the only one who actually responded and answered the question I asked - "Does it support code signing tokens?". The author responded, "Actually I use my (Digicert) JC Token via VirtualHere to sign VirtualHere when I build VirtualHere inside a VM." Good enough for me to give it a try!&lt;/p&gt;

&lt;p&gt;The VH Server runs on Windows, Linux, MacOS, a bunch of NAS servers, even a Raspberry Pi! The server licence is locked to the host machine, so if you decide to move the USB token to another host you will need to purchase another license - but at USD$49 that probably won't break the bank!&lt;/p&gt;

&lt;p&gt;I installed the VH server software on my XCP-ng host - installation was trivial and took all of 2 minutes (I'm no Linux expert). I then plugged the USB token in (the server is in my mini rack at home) and installed the VirtualHere client software on my Windows machine.&lt;/p&gt;

&lt;p&gt;The VH client can auto detect servers, however in my case the two machines were on different subnets, so I had to manually specify it. With the trial version, a message box shows up when it first connects. The client immediately showed a tree of the USB devices plugged into the server. The SafeNet token shows up as Token JC, right-click on it and select "Auto use this device" so it connects automatically. When I did this, the familiar Windows sound indicated a device had plugged in. I already had the SafeNet software installed so it didn't prompt me for drivers etc.&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/codesign-usb/virtualhere-client.png" /&gt;&lt;/p&gt;

&lt;p&gt;The last step in this USB remoting journey was to install the client as a service (right click on the USB Hubs node). This can only connect to licensed servers, so leave this step until you have purchased.&lt;br /&gt;
&lt;br /&gt;
&lt;strong&gt;NOTE&lt;/strong&gt; : I didn't make it clear before, but the VH client and token client software need to be installed on the machine where the signing takes place, ie your build machine or build agent machine. &lt;/p&gt;

&lt;h2&gt;Prompting for Passwords&lt;/h2&gt;

&lt;p&gt;Another issue with the USB tokens being present during code signing, is they also expect a human to be present - a password prompt is shown. That flies in the face of conventional wisdom - automate all the things!&lt;/p&gt;

&lt;p&gt;Fortunately, for the SafeNet token at least, there is a work around for this.&lt;/p&gt;

&lt;p&gt;Open the Safenet Authentication Client Tools, click on the Advanced View button (the gear). You may be prompted for the token password if you haven't already entered it. In the tree on the left, right-click on the certificate (under User certificates) and select Export certificate. Just to be clear here, this is the certificate without the private key (which stays on the token) - you can't use this exported certificate on a machine that does not have access to the USB token. &lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/codesign-usb/safenetvalues.png" /&gt;&lt;/p&gt;

&lt;p&gt;In the certificate view, under Private Key, take note of the Cryptographic Provider value (likely "eToken Base Cryptographic Provider" and the Container Name (p11#xxxxxxxxxxx). You will have to manually type them out somewhere as it doesn't support the clipboard. Save those values somewhere - as you will need them in your build process for code signing.&lt;/p&gt;

&lt;p&gt;Whilst still in the Client tools, select Client Settings and go to the Advance tab, check the "Enable single Login" and "Enable single Logon for PKCS#11." options, and set Automatic Logoff to Never - then hit Save. You can close the client now.&lt;/p&gt;

&lt;h2&gt;Code Signing&lt;/h2&gt;

&lt;p&gt;With all that done, we can use Signtool action in FinalBuilder. The Signing option tab is where those values we saved earlier come into play.&lt;/p&gt;

&lt;p&gt;The only difficult one is the Private Key container. Fortunately, some clever person on StackOverflow figure out the required format:&lt;/p&gt;

&lt;p&gt;[{{%CSPWD%}}]=p11#xxxxxxxxxx&lt;/p&gt;

&lt;p&gt;I have used a variable CSPWD for the token password.&lt;/p&gt;

&lt;p style="text-align: center"&gt;&lt;img src="https://cdn.finalbuilder.com/blog/vincent/codesign-usb/signtooloptions.png" /&gt;&lt;/p&gt;

&lt;p&gt;That's it. In my tests I have run FinalBuilder from the Windows task scheduler while logged out, and from a Continua CI build agent service (again while logged out) and it worked in both instances. I did a bunch of login/out/reboot testing and it continued to work. VirtualHere has been flawless. The next step is to configure our CI agents to access the USB token over VPN. Sadly our EV token is about to expire (and we never used it once in production, our OV cert still has another year left) - so I first have to jump through the validation hoops to get a new one.&lt;/p&gt;

&lt;p&gt;When using this technique on a CI server, you will need to take care that only one build at a time is using the token. In Continua CI, that is trivial to achieve using a &lt;a href="https://wiki.finalbuilder.com/display/continua/Shared+Resources" target="_blank"&gt; shared resource lock.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would love to test out some of the cloud HSM services too, but purchasing a certificate for each one is too rich for me. If you are using any of those with a cloud-based HSM, jump on our forums and let us know your experiences. If you experiment with or get up and running using VH let us know how it went - I might do a follow up post as we all gain more experience with usb tokens and code signing.&lt;/p&gt;

&lt;h2&gt;Warning (added 19 Oct 2022)&lt;/h2&gt;

&lt;p&gt;I probably should have pointed out that most tokens are configured to lock you out after too many authentication failures. So if you are getting auth failures when setting this up, stop, and manually login to the token to reset the failed count. &lt;/p&gt;

&lt;h2&gt;Rant&lt;/h2&gt;

&lt;p&gt;CA's (and their resellers) have some of the worst websites I have ever had the displeasure of reading. Pages and pages of useless or contradictory information with links promising more information that take you around in circles. Grrrrr. &lt;/p&gt;
</description><guid isPermaLink="false">845</guid></item><item><title>Continua CI System Server Properties</title><link>https://www.finalbuilder.com/resources/blogs/postid/844/continua-ci-server-properties</link><category>Continua CI,Delphi,FinalBuilder,General</category><pubDate>Thu, 13 May 2021 12:59:28 GMT</pubDate><description>&lt;p&gt;If you are using Continua for your CI, (and if not why not?) ensure that you check out &lt;a href="https://wiki.finalbuilder.com/x/BYDp"&gt;System Server Properties&lt;/a&gt;. These allow access to global settings which do not fit on any existing page.&lt;/p&gt;
&lt;p&gt;They can be used to configure several aspects of the UI and build process to fit your team preferences. This could simply be the number items to show per page on each of the dashboard views (&lt;em&gt;Server.ProjectsView.*.PageSize&lt;/em&gt;), or more complex patterns for detecting errors and warnings in actions settings (&lt;em&gt;Actions.Messages.*Patterns&lt;/em&gt;). Some system server properties are rarely needed, but some can be considered essential, such as &lt;em&gt;Server.HostUrl&lt;/em&gt; which can be used to ensure the links in notifications go to the correct external host name.&lt;/p&gt;

&lt;p&gt;We have recently added some new server properties which allow you to control the tabs on the Queue Options dialog (&lt;em&gt;Server.QueueOptionsDialog.*&lt;/em&gt;) and create a banner for displaying a message to all (or a subset of) users (&lt;em&gt;Server.Banner.*&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Here is the result of changing &lt;em&gt;Server.QueueOptionsDialog.TabSequence&lt;/em&gt; from "Variables,Repositories,Options"&lt;/p&gt;

&lt;p&gt;&lt;img alt="Queue Options dialog tabs - Variables first" src="https://cdn.finalbuilder.com/blog/daves/serverprops/queueoptionsvariablesfirst.png" /&gt;&lt;/p&gt;

&lt;p&gt;to "Repositories,Variables,Options".&lt;/p&gt;

&lt;p&gt;&lt;img alt="Queue Options dialog tabs - Variables first" src="https://cdn.finalbuilder.com/blog/daves/serverprops/queueoptionsrepositoriesfirst.png" /&gt;&lt;/p&gt;

&lt;p&gt; &lt;/p&gt;

&lt;p&gt;This is what happens to an existing banner when you change the &lt;em&gt;Server.Banner.MessageType&lt;/em&gt; from "Information"&lt;/p&gt;

&lt;p&gt;&lt;img alt="Information Banner" src="https://cdn.finalbuilder.com/blog/daves/serverprops/informationbanner.png" /&gt;&lt;/p&gt;

&lt;p&gt;to "Warning".&lt;/p&gt;

&lt;p&gt;&lt;img alt="Warning Banner" src="https://cdn.finalbuilder.com/blog/daves/serverprops/warningbanner.png" /&gt;&lt;/p&gt;

&lt;p&gt;Server properties can be edited on the "Continua Server - Properties" page located in the "Administration" section of Continua CI. See our documentation for &lt;a href="https://wiki.finalbuilder.com/x/BYDp"&gt;details on all the currently available server properties&lt;/a&gt;.&lt;/p&gt;
</description><guid isPermaLink="false">844</guid></item><item><title>DPM Package Manager - Progress update</title><link>https://www.finalbuilder.com/resources/blogs/postid/842/dpm-package-manager-progress-update</link><category>Delphi,DPM</category><pubDate>Wed, 24 Feb 2021 10:46:15 GMT</pubDate><description>        &lt;p&gt;In December 2019, I &lt;a href="/resources/blogs/introducing-dpm-a-package-manager-for-delphi" target="_blank"&gt;blogged&lt;/a&gt; about a package manager for Delphi that I am working on. This post is
            a progress update that shows where it's at and what's left to do to get to v1.&lt;/p&gt;

        &lt;h3&gt;DPM Recap&lt;/h3&gt;

        &lt;p&gt;
            For those not familiar with what I am trying to achieve here, I highly recommend reading my original &lt;a href="/resources/blogs/delphi-package-manager-rfc" target="_blank"&gt;
                Delphi Package Manager RFC&lt;/a&gt; post. In that post I detailed my ideas, and some of the challenges that Delphi presents when compared to other development environments.
        &lt;/p&gt;

        &lt;p&gt;
            In December 2019, the bare bones of DPM were there. We had a command line tool and that was it. We were able to create packages, install packages (and their dependencies) and restore them
            (restore ensures all referenced packages are present). Oh and we could list the available packages in our package feed (a folder).
        &lt;/p&gt;

        &lt;h3&gt;IDE Integration&lt;/h3&gt;

        &lt;p&gt;
            In the last 13 months there were around 175 commits to the DPM repository. In that time I have added an IDE plugin (that works in Delphi XE2 to 10.4). This involved the creation of several
            custom controls (I wasn't able to bend any existing ones to work how I wanted it to).
        &lt;/p&gt;

        &lt;p&gt;
            In addition to the work in the project repository, I also published &lt;a href="https://github.com/vsoftTechnologies/" target="_blank"&gt;several useful libraries&lt;/a&gt; that I needed for this
            project. DPM is now bootstrapped, to build DPM you need DPM, as it requires several libraries that are referenced as dpm packages.
        &lt;/p&gt;

        &lt;p&gt;
            In Nov 2020 I published the first alpha release that included an installer (code signed by VSoft Technologies) for installing both the command line tool and the IDE plugin (single
            installer, you can choose which IDE versions to install for). The installer allows you to install for the current user, or for all users (requires elevation to install).
        &lt;/p&gt;

        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/dpm-progress/installer.png"&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;
            I also did a zoom presentation about DPM to the Melbourne chapter of the Australian Delphi Users Group - a recording of that (long) presentation can be found &lt;a
               href="https://www.youtube.com/watch?v=TjVAMLfhgLo" target="_blank"&gt;here&lt;/a&gt;.
        &lt;/p&gt;

        &lt;p&gt;
            Adding IDE support for DPM was a massive undertaking. I had very little experience in developing Delphi IDE plugins (using the tools api) - and there were lots of subtle changes between
            delphi versions, getting things working correctly in 12 versions of Delphi was not easy. In particular, with the later versions of Delphi IDE that use VCL themes, getting things to look
            right (ie like a native part of the IDE) was a challenge.
        &lt;/p&gt;

        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/dpm-progress/dpm-ide.png"&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;The above image shows the installed packages for one of the projects in the project group, you get to this view by right clicking on the project node, or the DPM Packages node in the
            Project tree. &lt;/p&gt;
        &lt;p&gt;Note the view only shows the directly installed packages, not the transient dependencies - those you can see in the project tree under the DPM Packages node.&lt;/p&gt;
        &lt;p&gt;Before you can use DPM in the IDE, you need to configure a package source (a folder where your package files will live)&lt;/p&gt;
        &lt;p&gt;This can be done fron the command line&lt;/p&gt;
        &lt;pre&gt;dpm sources add -name=local -source=path to the folder you created&lt;/pre&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;Or from the IDE Settings&lt;/p&gt;
        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/dpm-progress/dpm-settings.png"&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;h3&gt;Compile during install&lt;/h3&gt;
        &lt;p&gt;
            The most recent updates added support for compiling packages during first install. Packages need to declare how to build in their dspec file, and dpm will use that and call msbuild to
            compile the packages if needed. DPM also records a bill of materials file (package.bom) in the package cache so that it can tell whether the package needs to be recompiled or not.
        &lt;/p&gt;

        &lt;p&gt;On first install, packages that are being compiled during the install process will take a little longer, but on subsequent installs or restores, the process is almost instant (a few ms).
        &lt;/p&gt;

        &lt;p&gt;
            Prior to adding this feature, building dpm on our Continua CI build agents took 13 minutes, much of which was taken up with compiling the dpm packages that it references (in particular,
            earlier versions of Delphi were very slow with spring4d). Since updating dpm on our agents with the new version, the entire build process for DPM (console app and 12 versions of the IDE
            plugin and the installer) takes less than 2 minutes.
        &lt;/p&gt;
        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/dpm-progress/dpm-build-times.png"&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;h3&gt;Missing features&lt;/h3&gt;

        &lt;h4&gt;Project group support&lt;/h4&gt;

        &lt;p&gt;
            When installing packages, the dependency resolution code does not know about other projects in the project group, or what packages and versions they reference. This
            will be a problem for packages that include design time components that need to be loaded - the IDE can only load 1 version of a design time package. This is what I am currently working
            on.
        &lt;/p&gt;

        &lt;h4&gt;Design time packages&lt;/h4&gt;
        &lt;p&gt;DPM does not currently install design time packages into the IDE. This is dependent on project group support, so it's next on the list after project group support.&lt;/p&gt;

        &lt;h4&gt;Package Updates&lt;/h4&gt;
        &lt;p&gt;The ability to detect when package updates are available and make it easy to install those updates. There's an Updates tab in the IDE but it's non functional at this time.&lt;/p&gt;

        &lt;h4&gt;Package Repository&lt;/h4&gt;

        &lt;p&gt;In it's current state, DPM only supports folder based package feeds. This works fine, but it does have some limitations&lt;/p&gt;
        &lt;ul&gt;
            &lt;li&gt;Limted search abilities - limted to searching on the package filenames.&lt;/li&gt;
            &lt;li&gt;You have to download packages to a folder.&lt;/li&gt;
            &lt;li&gt;Package Authors have to host the package files somewhere (mine are under releases on their github projects).&lt;/li&gt;
        &lt;/ul&gt;
        &lt;p&gt;I have made a start on the Package Repository, but not a lot of progress since I'm focusing on the client site right now.&lt;/p&gt;

        &lt;h3&gt;Q &amp; A&lt;/h3&gt;

        &lt;h4&gt;Is it usable?&lt;/h4&gt;
        &lt;p&gt;In it's current state, it's only usable for non visual libraries. As I mentioned, the DPM projects all use DPM themselves, and
            we have DPM actions in FinalBuilder for running the Pack and Restore commands. &lt;/p&gt;
        &lt;p&gt;If you use any of my open source libraries like DUnitX, Delphi Mocks etc, I have created packages for all of those libraries, and also
            created mirror projects (just for hosting the package files) for some other popular libraries like Spring4D. &lt;/p&gt;
        &lt;p&gt;I would encourage library authors in particular to take a look and provide feedback.&lt;/p&gt;

        &lt;h4&gt;Where can we find it?&lt;/h4&gt;
        &lt;p&gt;DPM is an open source project on &lt;a href="https://github.com/DelphiPackageManager/DPM" target="_blank"&gt;GitHub&lt;/a&gt;, the installer can be found under &lt;a
               href="https://github.com/DelphiPackageManager/DPM/releases" target="_blank"&gt;Releases&lt;/a&gt;
            (under each release, there is an Assets dropdown section).&lt;/p&gt;
        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/dpm-progress/installer-location.png"&gt;
        &lt;p&gt;&lt;/p&gt;

        &lt;h4&gt;What versions of Delphi does it support?&lt;/h4&gt;
        &lt;p&gt;Delphi XE2 to 10.4.2 - note that we compile with the latest updates installed for each compiler version. &lt;/p&gt;

        &lt;h4&gt;Why is it taking so long?&lt;/h4&gt;
        &lt;p&gt;Yes, someone asked that recently! This is a side project, free and open source. My primary focus is on running my business and working on our products (that keeps the lights on).&lt;/p&gt;

        &lt;h4&gt;Can we sponsor the project?&lt;/h4&gt;
        &lt;p&gt;Not right now, however it's something I'll look at in the future. &lt;/p&gt;

        &lt;h4&gt;Can we help?&lt;/h4&gt;
        &lt;p&gt;Absolutely. Fork the project on GitHub and clone it to your dev machine and spend some time getting to know the source code. Before making any pull requests, create an issue on github
            to discuss your ideas and make sure we on the same wavelength!&lt;/p&gt;</description><guid isPermaLink="false">842</guid></item><item><title>Advice for Delphi library authors</title><link>https://www.finalbuilder.com/resources/blogs/postid/841/advice-for-delphi-library-authors</link><category>Delphi,DPM</category><pubDate>Wed, 24 Feb 2021 00:57:00 GMT</pubDate><description>        &lt;p&gt;We use many third-party Delphi libraries to build FinalBuilder and Automise, and that brings plenty of issues when upgrading compiler versions. I've been using Delphi since 1995, both as a
            developer and as a component vendor, I have learned a thing or two about creating libraries that I would like to share. These are all ideas that make life easier for users, and make it
            easy to migrate from one version of Delphi to another.&lt;/p&gt;
        &lt;p&gt;There's no hard and fast rules on how Delphi Libraries are &lt;i&gt;supposed to be&lt;/i&gt; structured, these are just my preferences and things I have learned over the years. Hopefully this will
            help new and existing library authors.&lt;/p&gt;

        &lt;h3&gt;Folder Structure&lt;/h3&gt;
        &lt;p&gt;Keep the Source and the Packages in separate folders, this makes it easier to find the correct packages to compile, e.g :
        &lt;pre&gt;\Source
\Packages
\Demos&lt;/pre&gt;
        &lt;/p&gt;
        &lt;p&gt;Under Packages, create a folder for each compiler version your library supports, e.g:
        &lt;pre&gt;\Packages\Rad Studio XE8
\Packages\Rad Studio 10.0
\Packages\Rad Studio 10.1&lt;/pre&gt;
        &lt;/p&gt;
        &lt;h3&gt;Package Names&lt;/h3&gt;

        &lt;p&gt;Please, &lt;b&gt;do not&lt;/b&gt; put the Delphi version in the package project names.&lt;/p&gt;
        &lt;h4&gt;Bad!!!&lt;/h4&gt;
        &lt;pre&gt;MyProjectRun_D10_4.dproj
MyProjectDesign270.dproj&lt;/pre&gt;
        &lt;h4&gt;Good&lt;/h4&gt;
        &lt;pre&gt;MyProjectRun.dproj
MyProjectR.dproj
MyProjectDesign.dproj
MyProjectD.dproj&lt;/pre&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;Why not put the compiler version in the package project name you might ask? Well the answer is that it makes upgrading compiler versions a major pain for users who link their
            projects with Runtime Packages (yes, that includes us).&lt;/p&gt;

        &lt;p&gt;The reason is that when you compile a package, it creates a packagename.dcp file and that is what your project references. So, if your package name is MyPackageRun_D10_4 then that is what
            will be added to projects that use it.&lt;/p&gt;


        &lt;pre class="brush:delphi; toolbar:false;"&gt;
package MyOwnPackage;
//...
requires
  rtl,
  vcl,
  MyPackageRun_D10_4,
  AnotherPackage_Sydney,
  YetAnotherPackage_D104,
//  ...
        &lt;/pre&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;When Delphi 10.5 comes out, guess what the user has to do to upgrade their projects.... Yep, replace that all those package references with 10.5 versions (and the multitude of suffixes).
            Multiply that by a number
            of
            projects and a number of libraries (each with potentially multiple runtime packages) and you can see why this might be a pain.&lt;/p&gt;

        &lt;p&gt;Now you might say, but we don't want 15 versions of MyPackageRun.bpl laying about on users machines, and you would be right. The solution to this is a feature that has been around
            since Delphi 6 (2001) - &lt;a href="https://docwiki.embarcadero.com/RADStudio/Sydney/en/Compiler_directives_for_libraries_or_shared_objects_(Delphi)" target="_blank"&gt;LIBSUFFIX&lt;/a&gt;.&lt;/p&gt;
        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/advice-for-d/libsuffix.png" alt="LIBSUFFIX"&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;Setting LIBSUFFIX (on the Description section of project settings) will append the specified suffix to the BPL file name. So a suffix of _D10_4 will result in a package :&lt;/p&gt;
        &lt;pre&gt;MyPackageRun_D10_4.bpl&lt;/pre&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;however, the DCP file will still be generated as :&lt;/p&gt;
        &lt;pre&gt;MyPackageRun.dcp&lt;/pre&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;Remember it's the dcp file that our projects reference (for linking) - so by keeping the dcp file the same for all delphi versions, upgrading to a new compiler version just got a whole lot
            easier!&lt;/p&gt;

        &lt;p&gt;So when Delphi 10.5 comes out in the future, all I need to do is install the packages, no changes to my projects.&lt;/p&gt;

        &lt;p&gt;&lt;b&gt;Update&lt;/b&gt; : Someone pointed out that Delphi 10.4.1 support LIBSUFFIX $(Auto) - this will use the Delphi defined PackageVersion - which for 10.4 is 270. This is a nice addition 
            as it makes upgrading the package projects simpler. Of course if you don't like the PackageVersion suffix and use a custom one, then this is not for you.&lt;/p&gt;

        &lt;h3&gt;Use Explicit rebuild, not Rebuild as needed&lt;/h3&gt;
        &lt;p&gt;Have you ever encountered the error
        &lt;pre&gt;E2466 Never-build package 'XXX' requires always-build package 'YYY'&lt;/pre&gt;
        What this means is, a package, set to Expicit rebuild, references another package, set to 'Rebuild as needed', and it's a pain in the proverbial. Rebuild as needed is also referred to
        as Implicit Build - in dpk's you will see it as
        &lt;pre&gt;{$IMPLICITBUILD ON}&lt;/pre&gt;
        If that "Rebuild as needed" package is not part of your project group, guess what, you get to waste time closing and opening projects trying to get it to compile.
        &lt;/p&gt;
        &lt;p&gt;I'm sure someone will correct me on this, but I cannot see a good reason to have "Rebuild as needed" set. I suspect this is a hangover from before the Delphi IDE
            allowed you to specify &lt;a href="https://docwiki.embarcadero.com/RADStudio/Sydney/en/Project_Dependencies" target="_blank"&gt;Project Dependencies&lt;/a&gt; and it slows down builds.
        &lt;/p&gt;

        &lt;h3&gt;Use Search Paths for includes&lt;/h3&gt;

        &lt;p&gt;I often see includes with either hard coded paths, or relative paths like this :&lt;/p&gt;
        &lt;pre class="brush:delphi; toolbar:false;"&gt;
{$I '..\..\MyDefines.inc'}
        &lt;/pre&gt;
        &lt;p&gt;That's great, if the installer delivers the files in the right place - but they often don't - I hit this issue today, where the package just would not compile. I eventually
            figured out that the relative path was wrong.
        &lt;/p&gt;

        &lt;p&gt;There's a simple fix for this, and that is to remove the path in the $I statement, and use the Project Search Paths feature instead. &lt;/p&gt;

        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/advice-for-d/searchpath.png" alt="Search Paths"&gt;
        &lt;p&gt;&lt;/p&gt;
        &lt;p&gt;I have also seen libraries where there are mulitple copies of the include file and they are slightly different!&lt;/p&gt;

        &lt;h3&gt;Mark packages as Runtime only or Designtime only&lt;/h3&gt;
        &lt;p&gt;Some libraries have their packages marked as "Runtime and Designtime" (the default) - the impact of this is only minor, but it's a pet peeve of mine. The Delphi IDE (in recent versions at
            least) provides a nice indication of whether packages are runtime or designtime in the project tree, and for designtime packages, whether they are installed. &lt;/p&gt;
        &lt;p&gt;This makes it simple for me to determine which ones need to be installed or not.&lt;/p&gt;
        &lt;p&gt;Not Installed&lt;/p&gt;
        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/advice-for-d/not-installed.png" alt="Not Installed"&gt;
        &lt;p&gt;Installed&lt;/p&gt;
        &lt;img src="https://cdn.finalbuilder.com/blog/vincent/advice-for-d/installed.png" alt="Installed"&gt;
        &lt;p&gt;&lt;/p&gt;

        &lt;h3&gt;Summing up&lt;/h3&gt;

        &lt;p&gt;One of the major reasons people do not upgrade Delphi versions is because it's too hard to deal with the third party libraries and all the changes required just to
            get to the point of compiling. That eventually results in a lack of Delphi sales which results in a lack of investment in Delphi which feeds back into.... well you get the idea ;)&lt;/p&gt;

        &lt;p&gt;Making third party libraries easier to work with in Delphi has been a bit of a crusade for me, I've been &lt;a href="/resources/blogs/delphi-package-manager-rfc"&gt;working on this for a while
                now&lt;/a&gt;,
            and I'm getting closer to a solution - &lt;a href="https://github.com/DelphiPackageManager/DPM"&gt;DPM - A package manager for Delphi&lt;/a&gt; - if you are a library author, I encourage you
            to take a look. For examples on how to create a package spec (dspec) take a look at our open source projects &lt;a
               href="https://github.com/vsoftTechnologies/"&gt;https://github.com/vsoftTechnologies/&lt;/a&gt;
        &lt;/p&gt;
</description><guid isPermaLink="false">841</guid></item><item><title>Announcing the Release of Continua CI Version 1.9.2</title><link>https://www.finalbuilder.com/resources/blogs/postid/840/introducing-the-release-of-continua-ci-version-192</link><category>Continua CI,Delphi</category><pubDate>Mon, 09 Nov 2020 06:16:32 GMT</pubDate><description>&lt;p&gt;We are delighted to announce that &lt;a href="/downloads/continuaci/continua-ci-version-history-v192" target="_blank"&gt;version 1.9.2 of Continua CI&lt;/a&gt; has passed through the beta and release candidate stages, and has now been released. Here is a reminder of the new features in v1.9.2:&lt;/p&gt;

&lt;ul&gt;
	&lt;li&gt;&lt;a href="#export-and-import"&gt;&lt;b&gt;Export and Import&lt;/b&gt;&lt;/a&gt;: You can now export one or more configurations to a file and import them back from the file into Continua CI.&lt;/li&gt;
	&lt;li&gt;&lt;a href="#requeuing-stages"&gt;&lt;b&gt;Requeuing Stages&lt;/b&gt;&lt;/a&gt;: Requeue a failing stage without restarting the build.&lt;/li&gt;
	&lt;li&gt;&lt;a href="#multiple-daily-cleanup-rules"&gt;&lt;b&gt;Multiple Daily Cleanup Rules&lt;/b&gt;&lt;/a&gt;: Each type of build by-product can now have a different shelf life.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;&lt;a name="export-and-import"&gt;Export and Import&lt;/a&gt; &lt;a class="up-link" href="#" title="Go to top"&gt;&lt;img src="https://cdn.finalbuilder.com/i/up-icn.png" /&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Users with Configuration Edit permissions can now export one or more project configurations to a YAML or JSON file. This may be for backup, versioning or migration to another server.&lt;/p&gt;

&lt;p&gt;The export wizard has a number of steps allowing selection of one or more configurations, and also any related repositories, variables and shared resources.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Export Wizard - Configuration Selection" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/export_resized.png" /&gt;&lt;/p&gt;

&lt;p&gt;The configuration details can be exported to YAML or JSON file formats, according to your preferences for readability and differencing.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Export Wizard - File Details" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/export-file-details_resized.png" /&gt;&lt;/p&gt;

&lt;p&gt;The resultant file is downloaded to your computer, allowing you to file it away until you need it.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Export Wizard - Downloaded File" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/export-download.png" /&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt="Export Wizard - YAML" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/export-yaml.png" /&gt;&lt;/p&gt;

&lt;p&gt;The import wizard also consists of several steps, allowing users with Project Edit permissions to upload a file, ...&lt;/p&gt;

&lt;p&gt;&lt;img alt="Import Wizard - File Selection" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/import-file-details_resized.png" /&gt;&lt;/p&gt;

&lt;p&gt;choose which items in the file to import and whether to overwrite any existing matching items of create new items.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Import Wizard - Configuration Selection" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/import-configurations_resized.png" /&gt;&lt;/p&gt;

&lt;p&gt;The import runs in a transaction, so if any modified file content fails validation it will rollback...&lt;/p&gt;

&lt;p&gt;&lt;img alt="Import Wizard - Import Failed" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/import-failed_resized.png" /&gt;&lt;/p&gt;

&lt;p&gt;allowing you to make changes and retry.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Export Wizard - Import Complete" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/import-complete_resized.png" /&gt;&lt;/p&gt;

&lt;h2&gt;&lt;a name="requeuing-stages"&gt;Requeuing Stages&lt;/a&gt; &lt;a class="up-link" href="#" title="Go to top"&gt;&lt;img src="https://cdn.finalbuilder.com/i/up-icn.png" /&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Sometimes a build stage may fail due to external influences. It could be that a file server was offline, network connectivity was down, or a file was locked for access. If it has taken several long stages to get to this point, then having to run the whole build again from the start can be a pain.&lt;/p&gt;

&lt;p&gt;The last stage of a completed build can now be requeued, providing that it has failed, stopped or errored, and the server workspace is intact.&lt;/p&gt;

&lt;p&gt;If no parts of the server workspace have been removed by the cleanup process, then a Requeue Stage button will be shown after the last stage in the Stages list on the Build page.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Action list categories" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/requeue-stage-button.png" /&gt;&lt;/p&gt;

&lt;p&gt;This allows you to requeue and execute the stage again!&lt;/p&gt;

&lt;p&gt;&lt;img alt="Action list search" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/requeue-stage-running.png" /&gt;&lt;/p&gt;

&lt;p&gt;You can also optionally make changes to the stage actions and requeue the stage with the latest changes.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Stages" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/requeue-stage-dialog.png" /&gt;&lt;/p&gt;

&lt;h2&gt;&lt;a name="multiple-daily-cleanup-rules"&gt;Multiple Daily Cleanup Rules&lt;/a&gt; &lt;a class="up-link" href="#" title="Go to top"&gt;&lt;img src="https://cdn.finalbuilder.com/i/up-icn.png" /&gt;&lt;/a&gt;&lt;/h2&gt;

&lt;p&gt;Every build that is executed within Continua CI stores information in the server's workspace, such as artifacts and build logs, and entries in the database. These by-products are vital for executing your build process and tracking build information, however, they can also take up considerable disk space over time and have a negative impact on database performance. The cleanup settings define the shelf life for the build by-products.&lt;/p&gt;

&lt;p&gt;Up until now, the cleanup settings have been quite limited - you could set up a single policy per configuration defining the build age and build limits for cleaning up either the database, the workspace, or both. Often, however you would want to cleanup the workspace files to save space, well before removing the build from the database. This update allows you to define multiple cleanup rules, with different shelf lives for each type of build by-product.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Cleanup rules" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/cleanuprules_resized.png" /&gt;&lt;/p&gt;

&lt;p&gt;Each rule can include one or more by-product to clean up.&lt;/p&gt;

&lt;p&gt;&lt;img alt="Cleanup rules dialog" class="dropShadow" src="https://cdn.finalbuilder.com/blog/daves/v1.9.2-release/cleanuprule.png" /&gt;&lt;/p&gt;

&lt;p&gt;Download the installers for Continua CI v1.9.2 from the &lt;a href="/downloads/continuaci" target="_blank"&gt;Downloads&lt;/a&gt; page&lt;/p&gt;
&lt;style type="text/css"&gt;ul.horizontal {
		overflow: auto;
		margin: 10px 0 0 0;
		}
		ul.horizontal li {
			  float: left;
			  margin-left: 2em
		}
.syntaxhighlighter {
    background-color: #eee !important;
    margin-top: 0 !important;
    padding: 10px;
    outline-style: dashed;
    outline-width: 1px;
    outline-color: #666;
    width: 97% !important;
}
.syntaxhighlighter .line.alt2 {
    background-color: #eee !important;
}
.syntaxhighlighter table td.code
{
    overflow-y: hidden !important;
}
.syntaxhighlighter .plain, .syntaxhighlighter .plain a
{
    color: #639099 !important;
}
h1 { margin-bottom: 0.6em !important;
}

.up-link {
 float: right
}

img.dropShadow
{
  -webkit-filter: drop-shadow(5px 5px 5px #222);
  filter: drop-shadow(5px 5px 5px #222);
  margin-bottom: 1em;
}
&lt;/style&gt;
</description><guid isPermaLink="false">840</guid></item></channel></rss>